I'm not understanding something about the interaction of map with
the algorithms. I've got a map whose value_type is another map.
I'd like to iterate through the map entries and add all the "sub-map"
entries to the "primary" map. I wrote a little testcase, attached
below. When I compile it with g++ 3.3.3, I get this:
boost-1_32/boost/mpl/pair.hpp: In instantiation of
`boost::mpl::second
David Greene wrote:
I'm not understanding something about the interaction of map with the algorithms. I've got a map whose value_type is another map. I'd like to iterate through the map entries and add all the "sub-map" entries to the "primary" map. I wrote a little testcase, attached below. When I compile it with g++ 3.3.3, I get this:
<schnipp>
What am I doing wrong?
Much thanks for the help!
-Dave
Here are the things I can find:
#include
#include #include #include #include #include #include #include using namespace boost; using namespace boost::mpl;
struct key1 {}; struct key2 {};
struct entry { typedef map
> types; };
Err, this isn't what you described. Your map has a value_type **with a nested member called types** that is a map.
typedef map
> map_types; typedef fold
::types, First of all, what is this?---------------------^^^^^ inserter<_1, insert<_1, _2> > > >::type result;
I can only assume you meant "::type," which leads to the second problem. Oh, I see it now; you're trying to get the "types" member out of the result of invoking value_type. Okay, to do that you need a metafunction that gets the types member: template <class Value> struct get_types { typedef Value::types type; }; now you can write: get_types< // The ::types member of value_type< // The "value" component map_types // (when in map_types) , _2 // of the current element being processed >
So, IIUC, your ForwardOp is trying to use the copy algorithm with an inserter to insert each element of the sequence returned by the above lambda expression. One other problem is that insert<_1, _2> will have its placeholders substituted immediately as the "fold" is evaluated. So for each step of the copy, the same state and element will be passed. You need to protect that placeholder expression from early substitution. The easiest way is to transform it into a metafunction class using the lambda metafunction: copy< get_types< // The ::types member of value_type< // The "value" component map_types // (when in map_types) , _2 // of the current element being processed > > , inserter< // an inserter starting with the outer state _1 // (the sequence being built) as its state. , lambda< // [preventing early substitution] insert<_,_> // and inserting each element into > // the inner state >
So that would be the lambda expression you pass to fold. But I would
tend just use a two-level fold:
typedef fold<
map_types // sequence
, map_types // initial state
fold<
get_types< // The ::types member of
value_type< // The "value" component
map_types // (when in map_types)
, _2 // of the outer element being processed
>
>
, _1 // starting with the outer state
, lambda
::type result;
HTH, -- Dave Abrahams Boost Consulting http://www.boost-consulting.com
David Abrahams wrote:
So, IIUC, your ForwardOp is trying to use the copy algorithm with an inserter to insert each element of the sequence returned by the above lambda expression. One other problem is that insert<_1, _2> will have its placeholders substituted immediately as the "fold" is evaluated. So for each step of the copy, the same state and element will be passed. You need to protect that placeholder expression from early substitution.
That makes sense (mostly). I don't quite grok the lambda stuff, _ and how it gets replaced with the "right" stuff but I guess that's part of the learning curve. I had tried writing the get_types metafunction before but it didn't help. The lambda part is what I was missing. Thanks! [But see below]
The easiest way is to transform it into a metafunction class using the lambda metafunction:
copy< get_types< // The ::types member of value_type< // The "value" component map_types // (when in map_types) , _2 // of the current element being processed > > , inserter< // an inserter starting with the outer state _1 // (the sequence being built) as its state. , lambda< // [preventing early substitution] insert<_,_> // and inserting each element into > // the inner state >
I tried this (replacing get_types with get_entries to reduce confusion):
struct entry {
typedef map
func;
typedef fold
David Greene wrote:
David Abrahams wrote:
So, IIUC, your ForwardOp is trying to use the copy algorithm with an inserter to insert each element of the sequence returned by the above lambda expression. One other problem is that insert<_1, _2> will have its placeholders substituted immediately as the "fold" is evaluated. So for each step of the copy, the same state and element will be passed. You need to protect that placeholder expression from early substitution.
That makes sense (mostly). I don't quite grok the lambda stuff, _ and how it gets replaced with the "right" stuff but I guess that's part of the learning curve.
insert<_,_> is equivalent to insert<_1,_2>
I had tried writing the get_types metafunction before but it didn't help. The lambda part is what I was missing. Thanks!
[But see below]
The easiest way is to transform it into a metafunction class using the lambda metafunction:
copy< get_types< // The ::types member of value_type< // The "value" component map_types // (when in map_types) , _2 // of the current element being processed > > , inserter< // an inserter starting with the outer state _1 // (the sequence being built) as its state. , lambda< // [preventing early substitution] insert<_,_> // and inserting each element into > // the inner state >
I tried this (replacing get_types with get_entries to reduce confusion):
struct entry { typedef map
> entries; }; template<typename Entry> struct get_entries { typedef typename Entry::entries type; };
typedef map
> map_types; typedef copy< get_entries< // The ::types member of value_type< // The "value" component map_types // (when in map_types) , _2 // of the current element being processed > > , inserter< // an inserter starting with the outer state _1 // (the sequence being built) as its state. , lambda< // [preventing early substitution] insert<_,_> // and inserting each element into > // the inner state >
func;
typedef fold
::type result; I believe this is equivalent to what you wrote. I also tried the nested fold version as well.
Now g++ complains about apply for both versions:
boost-1_32/boost/mpl/aux_/preprocessed/gcc/fold_impl.hpp: In instantiation of `boost::mpl::apply_wrap2
>': [Loads of "instatiated from" messages]
You left out the line that says "error:" and gives the error message.
BTW, I suggest you get STLFilt, which will move this error to the top.
But try using protect
::type I'm not positive that would work.
boost-1_32/boost/mpl/aux_/preprocessed/gcc/fold_impl.hpp:49: instantiated from `boost::mpl::apply2
>' boost-1_32/boost/mpl/aux_/preprocessed/gcc/fold_impl.hpp:49: instantiated from `boost::mpl::aux::fold_impl<1, boost::mpl::m_iter , boost::mpl::m_iter , map_types, func>' boost-1_32/boost/mpl/fold.hpp:39: instantiated from `boost::mpl::fold ' fold2.cc:51: instantiated from here boost-1_32/boost/mpl/aux_/preprocessed/gcc/fold_impl.hpp:49: error: no class template named `apply' in `struct map_types' There are other errors but I'm not sure how useful they are.
Thanks for your patience. I'm just getting back into MPL after about a year after being off-list.
HTH, -- Dave Abrahams Boost Consulting http://www.boost-consulting.com
David Abrahams wrote:
David Greene wrote:
David Abrahams wrote:
So, IIUC, your ForwardOp is trying to use the copy algorithm with an inserter to insert each element of the sequence returned by the above lambda expression. One other problem is that insert<_1, _2> will have its placeholders substituted immediately as the "fold" is evaluated. So for each step of the copy, the same state and element will be passed. You need to protect that placeholder expression from early substitution.
That makes sense (mostly). I don't quite grok the lambda stuff, _ and how it gets replaced with the "right" stuff but I guess that's part of the learning curve.
insert<_,_> is equivalent to insert<_1,_2>
I had tried writing the get_types metafunction before but it didn't help. The lambda part is what I was missing. Thanks!
[But see below]
The easiest way is to transform it into a metafunction class using the lambda metafunction:
copy< get_types< // The ::types member of value_type< // The "value" component map_types // (when in map_types) , _2 // of the current element being processed > > , inserter< // an inserter starting with the outer state _1 // (the sequence being built) as its state. , lambda< // [preventing early substitution] insert<_,_> // and inserting each element into > // the inner state >
I tried this (replacing get_types with get_entries to reduce confusion):
struct entry { typedef map
> entries; }; template<typename Entry> struct get_entries { typedef typename Entry::entries type; };
typedef map
> map_types; typedef copy< get_entries< // The ::types member of value_type< // The "value" component map_types // (when in map_types) , _2 // of the current element being processed >
, inserter< // an inserter starting with the outer state _1 // (the sequence being built) as its state. , lambda< // [preventing early substitution] insert<_,_> // and inserting each element into > // the inner state
func;
typedef fold
::type result; I believe this is equivalent to what you wrote. I also tried the nested fold version as well.
Now g++ complains about apply for both versions:
boost-1_32/boost/mpl/aux_/preprocessed/gcc/fold_impl.hpp: In instantiation of `boost::mpl::apply_wrap2
>': [Loads of "instatiated from" messages]
You left out the line that says "error:" and gives the error message. BTW, I suggest you get STLFilt, which will move this error to the top.
Actually, I didn't leave it out: boost-1_32/boost/mpl/aux_/preprocessed/gcc/fold_impl.hpp:49: error: no class template named `apply' in `struct map_types'
But try using protect
instead. I'm not sure that lambda<X> is derived from lambda<X>::type, and even if you used lambda ::type I'm not positive that would work.
You're right, that doesn't work:
/cray/iss/compiler/cost/tools/nv1-cray-unicosmp/include/boost-1_32/boost/mpl/aux_/insert_impl.hpp:
In instantiation of `boost::mpl::clear
David Greene wrote: <snip> Please try to limit the amount of quoted text in your posts.
I'll have to get STLFilt. Any hints on the above?
Not a clue. We'll have to ask Aleksey. Aleksey? -- Dave Abrahams Boost Consulting http://www.boost-consulting.com
David Abrahams writes:
Oh, I see it now; you're trying to get the "types" member out of the result of invoking value_type. Okay, to do that you need a metafunction that gets the types member:
template <class Value> struct get_types { typedef Value::types type; };
now you can write:
get_types< // The ::types member of value_type< // The "value" component map_types // (when in map_types) , _2 // of the current element being processed >
So, IIUC, your ForwardOp is trying to use the copy algorithm with an inserter to insert each element of the sequence returned by the above lambda expression. One other problem is that insert<_1, _2> will have its placeholders substituted immediately as the "fold" is evaluated. So for each step of the copy, the same state and element will be passed. You need to protect that placeholder expression from early substitution. The easiest way is to transform it into a metafunction class using the lambda metafunction:
copy< get_types< // The ::types member of value_type< // The "value" component map_types // (when in map_types) , _2 // of the current element being processed > > , inserter< // an inserter starting with the outer state _1 // (the sequence being built) as its state. , lambda< // [preventing early substitution] insert<_,_> // and inserting each element into > // the inner state >
Won't work. The 'lambda' metafunction doesn't have any special status here. For instance, 'lambda<_1>' is a regular, well, lambda expression, not different from, let's say, 'first<_1>'. It's all documented in the reference manual, and illustrated by the corresponding tests (e.g. http://cvs.sourceforge.net/viewcvs.py/boost/boost/libs/mpl/test/apply.cpp?vi...). Answering the OP question: MPL lambda expressions do not support scopes (yet), so it's not possible to implement the above without an auxiliary metafunction incapsulating the nested scope. Which actually might be a good thing -- it's hard to imagine that the "inline" version would be shorter and easier to understand than this: template< typename Map, typename Entry > struct copy_entires : copy< typename Entry::second::entries , inserter
Aleksey Gurtovoy wrote:
Answering the OP question: MPL lambda expressions do not support scopes (yet), so it's not possible to implement the above without an auxiliary metafunction incapsulating the nested scope. Which actually might be a good thing -- it's hard to imagine that the "inline" version would be shorter and easier to understand than this:
template< typename Map, typename Entry > struct copy_entires : copy< typename Entry::second::entries , inserter
typedef fold
>::type result;
In that case, can you explain what protect<> is for? Thanks, -- Dave Abrahams Boost Consulting http://www.boost-consulting.com
David Abrahams writes:
Aleksey Gurtovoy wrote:
Answering the OP question: MPL lambda expressions do not support scopes (yet), so it's not possible to implement the above without an auxiliary metafunction incapsulating the nested scope. Which actually might be a good thing -- it's hard to imagine that the "inline" version would be shorter and easier to understand than this:
template< typename Map, typename Entry > struct copy_entires : copy< typename Entry::second::entries , inserter
typedef fold
>::type result; In that case, can you explain what protect<> is for?
From http://www.boost.org/libs/mpl/doc/refmanual/protect.html:
'protect' is an identity wrapper for a Metafunction Class that
prevents its argument from being recognized as a bind expression.
Actually, the above definition is incomplete; should be:
'protect' is an identity wrapper for a Metafunction Class that
prevents its argument from being recognized as a bind/placeholder
expression.
The main usage for 'protect' is to prevent parametrized metafunction classes
from being accidentally treated as a placeholder expression simply because
their arguments happened to embed a placeholder. For instance:
template< typename Predicate > struct next_if
{
template< typename N, typename T >
struct apply
: eval_if<
typename apply1
Aleksey Gurtovoy wrote:
From http://www.boost.org/libs/mpl/doc/refmanual/protect.html:
'protect' is an identity wrapper for a Metafunction Class that prevents its argument from being recognized as a bind expression.
Actually, the above definition is incomplete; should be:
'protect' is an identity wrapper for a Metafunction Class that prevents its argument from being recognized as a bind/placeholder expression.
The main usage for 'protect' is to prevent parametrized metafunction classes from being accidentally treated as a placeholder expression simply because their arguments happened to embed a placeholder.
Hum. Seems a bit counterintuitive that protect doesn't apply equally well to this case. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com
David Abrahams writes:
Aleksey Gurtovoy wrote:
From http://www.boost.org/libs/mpl/doc/refmanual/protect.html:
'protect' is an identity wrapper for a Metafunction Class that prevents its argument from being recognized as a bind expression.
Actually, the above definition is incomplete; should be:
'protect' is an identity wrapper for a Metafunction Class that prevents its argument from being recognized as a bind/placeholder expression.
The main usage for 'protect' is to prevent parametrized metafunction classes from being accidentally treated as a placeholder expression simply because their arguments happened to embed a placeholder.
Hum. Seems a bit counterintuitive that protect doesn't apply equally well to this case.
??? As I tried to explain in my previous reply, 'protect' already has a well-defined semantics in lambda expressions, and it's quite different from what is needed to support "nested scopes". It would be nice to have a single magic primitive that would work the way you want it to work depending on the particular use case at hand, but I for one have no knowledge of how to implement one. -- Aleksey Gurtovoy MetaCommunications Engineering
Aleksey Gurtovoy wrote:
David Abrahams writes:
Aleksey Gurtovoy wrote:
'protect' is an identity wrapper for a Metafunction Class that prevents its argument from being recognized as a bind/placeholder expression.
The main usage for 'protect' is to prevent parametrized metafunction classes from being accidentally treated as a placeholder expression simply because their arguments happened to embed a placeholder.
Hum. Seems a bit counterintuitive that protect doesn't apply equally well to this case.
??? As I tried to explain in my previous reply, 'protect' already has a well-defined semantics in lambda expressions, and it's quite different from what is needed to support "nested scopes".
I understand that you said that, but to me what protect does (prevents the recognition and premature substition of placeholders) looks very similar to what the OP wants. Also, maybe it's just a failure of my imagination, but I have a hard time seeing what the OP wants as "nested scopes."
It would be nice to have a single magic primitive that would work the way you want it to work depending on the particular use case at hand, but I for one have no knowledge of how to implement one.
Well, that certainly is a real obstacle ;-) -- Dave Abrahams Boost Consulting http://www.boost-consulting.com
David Abrahams writes:
Aleksey Gurtovoy wrote:
David Abrahams writes:
Aleksey Gurtovoy wrote:
'protect' is an identity wrapper for a Metafunction Class that prevents its argument from being recognized as a bind/placeholder expression.
The main usage for 'protect' is to prevent parametrized metafunction classes from being accidentally treated as a placeholder expression simply because their arguments happened to embed a placeholder.
Hum. Seems a bit counterintuitive that protect doesn't apply equally well to this case.
??? As I tried to explain in my previous reply, 'protect' already has a well-defined semantics in lambda expressions, and it's quite different from what is needed to support "nested scopes".
I understand that you said that, but to me what protect does (prevents the recognition and premature substition of placeholders)
It doesn't prevent a "premature substition" of placeholders. It prevents it once and for all.
looks very similar to what the OP wants. Also, maybe it's just a failure of my imagination, but I have a hard time seeing what the OP wants as "nested scopes."
Reciting the rewrite of the OP code from my original reply: template< typename Map, typename Entry > struct copy_entires // scope #2 : copy< typename Entry::second::entries , inserter
Aleksey Gurtovoy wrote:
David Abrahams writes:
Hum. Seems a bit counterintuitive that protect doesn't apply equally well to this case.
??? As I tried to explain in my previous reply, 'protect' already has a well-defined semantics in lambda expressions, and it's quite different from what is needed to support "nested scopes". It would be nice to have a single magic primitive that would work the way you want it to work depending on the particular use case at hand, but I for one have no knowledge of how to implement one.
I'm sorry if I'm being thick here, but I can't grasp this. To me protect
looks exactly like what is needed here. I have always thought of
protect as delaying the placeholder substitution one step, so that:
typedef fold<
map_types
, map_types
, copy<
get_types<_2>
, inserter<_1, protect
::type result;
Would work. Changing the protect specialization in boost/mpl/preprocessed/gcc/full_lambda.hpp to this: template< typename T, typename Tag > struct lambda< mpl::protect<T>,Tag, int_<1> > { typedef false_ is_le; typedef T result_; typedef result_ type; }; Makes protect work like I thought it did, and makes the above compile. I don't really understand the workings of lambda, so this probably breaks something else. So what am I missing? Why can't it work like this? -- Daniel Wallin
Daniel Wallin writes:
Aleksey Gurtovoy wrote:
David Abrahams writes:
Hum. Seems a bit counterintuitive that protect doesn't apply equally well to this case.
??? As I tried to explain in my previous reply, 'protect' already has a well-defined semantics in lambda expressions, and it's quite different from what is needed to support "nested scopes". It would be nice to have a single magic primitive that would work the way you want it to work depending on the particular use case at hand, but I for one have no knowledge of how to implement one.
I'm sorry if I'm being thick here, but I can't grasp this. To me protect looks exactly like what is needed here. I have always thought of protect as delaying the placeholder substitution one step,
Well, again, it's not what it does. If we are to talk about introducing another primitive that would cover the OP use case, then it's another discussion (which should be taken to the developers list).
so that:
typedef fold< map_types , map_types , copy< get_types<_2> , inserter<_1, protect
> > > ::type result;
Would work. Changing the protect specialization in
boost/mpl/preprocessed/gcc/full_lambda.hpp
to this:
template< typename T, typename Tag > struct lambda< mpl::protect<T>,Tag, int_<1> > { typedef false_ is_le; typedef T result_; typedef result_ type; };
Makes protect work like I thought it did, and makes the above compile.
And breaks the code relying on the current semantics.
I don't really understand the workings of lambda, so this probably breaks something else.
Yes, it does.
So what am I missing? Why can't it work like this?
Because it's unspecified how many times a lambda expression is passed through the 'lambda' metafunction before the actual invocation takes place. -- Aleksey Gurtovoy MetaCommunications Engineering
participants (4)
-
Aleksey Gurtovoy
-
Daniel Wallin
-
David Abrahams
-
David Greene