[mpl] easy access to inherit_linearly elements

The code in: http://boost-sandbox.sourceforge.net/vault/inherit_linearly_test.cpp provides easy access to the elements of inherit_linearly with: get_tail<inherit_linearly<...>, i>::head_type which returns the i-th element in the inheritance heirarchy. Couldn't this be used to generate member names using templates? For example, the "name" of the i-th value on p. 191 of the _C++ Template Metaprogramming_ book would be: r.get_tail<inherit_linearly<...>, i>::head_type::value where r is an instance of: inherit_linearly<types, inherit_head_tail<wrap<_2>,_1> >::type

Larry Evans wrote:
The code in:
http://boost-sandbox.sourceforge.net/vault/inherit_linearly_test.cpp
provides easy access to the elements of inherit_linearly
?? inherit_linearly is a metafunction. It doesn't have elements. Maybe you mean the result of invoking it?
with:
get_tail<inherit_linearly<...>, i>::head_type
which returns the i-th element in the inheritance heirarchy. Couldn't this be used to generate member names using templates?
No, as the book says, there really is no way to generate member names using templates.
For example, the "name" of the i-th value on p. 191 of the
_C++ Template Metaprogramming_
book would be:
r.get_tail<inherit_linearly<...>, i>::head_type::value
That's not a name; it's an expression. Also, your sample code has no get_tail member template, so I don't see how that could compile...
where r is an instance of:
inherit_linearly<types, inherit_head_tail<wrap<_2>,_1> >::type
...that said, this doesn't seem like a particularly original idea. It seems like a complicated way of expressing what boost::tuples::get already provides. Am I missing something? -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

On 01/15/2005 10:11 AM, David Abrahams wrote:
Larry Evans wrote:
The code in:
http://boost-sandbox.sourceforge.net/vault/inherit_linearly_test.cpp
provides easy access to the elements of inherit_linearly
?? inherit_linearly is a metafunction. It doesn't have elements. Maybe you mean the result of invoking it?
Yes.
with:
get_tail<inherit_linearly<...>, i>::head_type
which returns the i-th element in the inheritance heirarchy. Couldn't this be used to generate member names using templates?
No, as the book says, there really is no way to generate member names using templates.
[snip]
book would be:
r.get_tail<inherit_linearly<...>, i>::head_type::value
That's not a name; it's an expression.
Well, sure, just as 1+1 is an expression, but it's an "alias" for 2, just as the expression r.x is an "alias" for element x in record r, or r[2] is an "alias" for the 2nd element in an array, or r.::tail_type::tail_type::head_type.value is an "alias" for 2nd element in a record like that in the example code. Maybe the definition of name I'm thinking about includes any compile-time evaluated expression. I can't remember where, but it was in some computer science textbook where expressions were called names for the result of the expression, and that's why I used the term "name". Besides, if an expression provides the same capability as a name, i.e. the ability to access the element, what's the importance of providing a "real name" (i.e. a c++ identifier) for the element? Anyway, my definition of name differs from yours, but if the only purpose is to provide a compile-time evaluated offset from some container, then both definitions satisfy the purpose.
Also, your sample code has no get_tail member template, so I don't see how that could compile...
I just downloaded it and it has get_tail specializations on lines 34 and 46. I've compiled it with intel 8.0 and maybe it's not standard, but I don't think the primary template needs to be defined if it's not used.
where r is an instance of:
inherit_linearly<types, inherit_head_tail<wrap<_2>,_1> >::type
...that said, this doesn't seem like a particularly original idea. It
True, but I'm not claiming it's originality, just that it allows access to the elements with the same runtime cost as that provided by a "real name".
seems like a complicated way of expressing what boost::tuples::get
It's no more complicated than that provided by tuples::get. It's just an adaptation of the same (or very similar, AFAICT) method to access the elements.
already provides. Am I missing something?
Just that the book seems to indicate there's a difficulty in accessing the elements which isn't really there, unless you define typing a long compile-time evaluated expression as difficult.

Larry Evans wrote:
On 01/15/2005 10:11 AM, David Abrahams wrote:
Larry Evans wrote:
which returns the i-th element in the inheritance heirarchy. Couldn't this be used to generate member names using templates?
No, as the book says, there really is no way to generate member names using templates.
[snip]
book would be:
r.get_tail<inherit_linearly<...>, i>::head_type::value
That's not a name; it's an expression.
Well, sure, just as 1+1 is an expression, but it's an "alias" for 2,
Not if you're interested in tokens.
just as the expression r.x is an "alias" for element x in record r, or r[2] is an "alias" for the 2nd element in an array, or r.::tail_type::tail_type::head_type.value is an "alias" for 2nd element in a record like that in the example code. Maybe the definition of name I'm thinking about includes any compile-time evaluated expression.
Maybe. The one I'm using comes from the C++ Standard: 3 Basic concepts [basic] .... 4 A name is a use of an identifier (2.10) that denotes an entity or label (6.6.4, 6.1). A variable is introduced by the declaration of an object. The variable's name denotes the object.
Besides, if an expression provides the same capability as a name, i.e. the ability to access the element, what's the importance of providing a "real name" (i.e. a c++ identifier) for the element?
None other than ease-of-use. The point of that note about names is to say you can't access an arbitrary member of that composed class by naming the member in the usual way, because all those members will have the same name, and that's unavoidable with TMP. Nothing more.
Anyway, my definition of name differs from yours, but if the only purpose is to provide a compile-time evaluated offset from some container, then both definitions satisfy the purpose.
Not really. My definition doesn't really allow for much compile-time evaluation.
Also, your sample code has no get_tail member template, so I don't see ^^^^^^^^^^^^^^^^^^^^^^^^ how that could compile...
I just downloaded it and it has get_tail specializations on lines 34 and 46.
The code in your posting used the construct r.get_tail< .... > I don't see how that can compile unless something is defined with a member template called "get_tail."
where r is an instance of:
inherit_linearly<types, inherit_head_tail<wrap<_2>,_1> >::type
...that said, this doesn't seem like a particularly original idea. It
True, but I'm not claiming it's originality, just that it allows access to the elements with the same runtime cost as that provided by a "real name".
seems like a complicated way of expressing what boost::tuples::get
It's no more complicated than that provided by tuples::get. It's just an adaptation of the same (or very similar, AFAICT) method to access the elements.
already provides. Am I missing something?
Just that the book seems to indicate there's a difficulty in accessing the elements which isn't really there, unless you define typing a long compile-time evaluated expression as difficult.
It's certainly more difficult than typing r.foo The book isn't making a very deep point there, but the point it does make is valid. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

On 01/15/2005 02:25 PM, David Abrahams wrote: [snip]
Maybe. The one I'm using comes from the C++ Standard:
OK. As I said below, our definitions differ.
3 Basic concepts [basic] .... 4 A name is a use of an identifier (2.10) that denotes an entity or label (6.6.4, 6.1). A variable is introduced by the declaration of an object. The variable's name denotes the object.
Besides, if an expression provides the same capability as a name, i.e. the ability to access the element, what's the importance of providing a "real name" (i.e. a c++ identifier) for the element?
None other than ease-of-use. The point of that note about names is to say you can't access an arbitrary member of that composed class by naming the member in the usual way, because all those members will have the same name, and that's unavoidable with TMP. Nothing more.
OK. I read the page differently. I thought it meant that there was difficult or impossible to access the elements. Then there's the sentence on p. 191: We can't access any other than the first one directly. OK, I guess "can't access directly" does not mean "can't access", but then consider the next paragraph: it's difficult to access the value member of a given type even by casting to an appropriate base class. This leaves me with the impression that it's "difficult" to access members other than the first; yet a template member function such as boost::tuple's, get<1>, doesn't seem difficult, at least to me.
Anyway, my definition of name differs from yours, but if the only purpose is to provide a compile-time evaluated offset from some container, then both definitions satisfy the purpose.
Not really. My definition doesn't really allow for much compile-time evaluation.
True, it's much simpler, but does involve compile-time evaluation of offset from the start of the structure.
Also, your sample code has no get_tail member template, so I don't see
^^^^^^^^^^^^^^^^^^^^^^^^
OK, the key work is *member*. I apologize. There is no member template.
how that could compile...
I've replaced the file with another, get_inherit_side_test.cpp, which, in test_instantiate(void), actually creates an instance of the tuple_type and accesses the 0-th element with: t.get_inherit_side<inherit_side_right,tuple_type,0>::type::left_type::value; Obviously, this could be shortened with a member template, t.get<0>() which simply returned the above expression. The uploaded code compiles with just a warning about t being used before it's defined.
I just downloaded it and it has get_tail specializations on lines 34 and 46.
The code in your posting used the construct
r.get_tail< .... >
I don't see how that can compile unless something is defined with a member template called "get_tail."
Sorry, I should have said: r.get_tail<...>::head_type::value; but then I would have had to provide the code like that in the newly uploaded file, and it didn't seem, at the time, necessary to demonstrate my point. [snip]
Just that the book seems to indicate there's a difficulty in accessing the elements which isn't really there, unless you define typing a long compile-time evaluated expression as difficult.
It's certainly more difficult than typing
r.foo
The book isn't making a very deep point there, but the point it does make is valid.
OK, but I, and maybe others, are interpreting the page as meaning inherit_linearly is less capable than tuple as far as accessing the elements. And with a member template, like boost's tuple, r.foo is not significantly more difficult than: r.get<foo>(); where foo is maybe an enumerator "naming" say the 2nd element in the tuple.

Larry Evans wrote:
OK. I read the page differently. I thought it meant that there was difficult or impossible to access the elements. Then there's the sentence on p. 191:
We can't access any other than the first one directly.
OK, I guess "can't access directly" does not mean "can't access",
Right.
but then consider the next paragraph:
it's difficult to access the value member of a given type even by casting to an appropriate base class.
This leaves me with the impression that it's "difficult" to access members other than the first; yet a template member function such as boost::tuple's, get<1>, doesn't seem difficult, at least to me.
It's not difficult if you have the function. In any case the code in the book is looking up a member by its type, not by its index.
I've replaced the file with another, get_inherit_side_test.cpp, which, in test_instantiate(void), actually creates an instance of the tuple_type and accesses the 0-th element with:
t.get_inherit_side<inherit_side_right,tuple_type,0>::type::left_type::value;
Obviously, this could be shortened with a member template,
t.get<0>()
which simply returned the above expression. The uploaded code compiles with just a warning about t being used before it's defined.
The code in your posting used the construct
r.get_tail< .... >
I don't see how that can compile unless something is defined with a member template called "get_tail."
Sorry, I should have said:
r.get_tail<...>::head_type::value;
That wouldn't have changed anything. I wasn't confused about the lack of something after ">" (heck, it might have been there for all I know). There was no member function template called get_tail, which makes the above just as un-compilable as whatever you wrote before.
but then I would have had to provide the code like that in the newly uploaded file, and it didn't seem, at the time, necessary to demonstrate my point.
It's certainly more difficult than typing
r.foo
The book isn't making a very deep point there, but the point it does make is valid.
OK, but I, and maybe others, are interpreting the page as meaning inherit_linearly is less capable than tuple as far as accessing the elements.
First of all, nothing in the book gives you any reason to think the text is saying it's difficult compared to working with boost::tuple. We don't even mention boost::tuple there. Second of all, by itself, of course the **result of invoking inherit_linearly** shown on that page is less capable than tuple, because there's no convenient access function like get<> provided. Finally, the kind of access being done is completely different from what's done with tuple. I think I'll wait to see if anyone else is confused by this before worrying about it. :o) -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

On 01/15/2005 05:26 PM, David Abrahams wrote:
Larry Evans wrote: [snip]
I've replaced the file with another, get_inherit_side_test.cpp, which, in test_instantiate(void), actually creates an instance of the tuple_type and accesses the 0-th element with:
t.get_inherit_side<inherit_side_right,tuple_type,0>::type::left_type::value; [snip]
The code in your posting used the construct
r.get_tail< .... >
I don't see how that can compile unless something is defined with a member template called "get_tail."
Sorry, I should have said:
r.get_tail<...>::head_type::value;
That wouldn't have changed anything. I wasn't confused about the lack of something after ">" (heck, it might have been there for all I know). There was no member function template called get_tail, which makes the above just as un-compilable as whatever you wrote before.
But the aforementioned t.get_inherit_side<...>:::type::left_type::value; does compile? OK, now I see. Instead of >::head_type, there should have been >::type::head_type. Does it make sense now? After all, it's no different than: t.super_type_expr::member_var_name; for some super_type_expr which access's some super_type of t and where member_var_name is some member variable defined in that super_type. Anyway, I've uploaded get_ith_head_test.cpp to sandbox/vault which does include the member function: template < typename Head , typename Tail
template<unsigned Depth> typename get_ith_tail <inherit_head_tail<Head,Tail>,Depth>::type::head_type const& inherit_head_tail<Head,Tail>:: get_ith_head(void)const {...} which does what tuple's get<Depth> does, AFAICT. The code compiles and passes the tests with both intel and gcc compilers. [snip]
OK, but I, and maybe others, are interpreting the page as meaning inherit_linearly is less capable than tuple as far as accessing the elements.
First of all, nothing in the book gives you any reason to think the text is saying it's difficult compared to working with boost::tuple. We don't even mention boost::tuple there.
True, but the reader can only assume: it's difficult to access the value member in the last paragraph of p. 191 meant difficult w.r.t. some "standard", which I assume was t.member_var_name or, in the case of the example from p. 191, t.value. I only chose tuple as a comparison candidate because I assumed you thought its element access was not "too difficult" w.r.t. the standard since the following post: http://article.gmane.org/gmane.comp.lib.boost.devel/116516 implied tuple's element access complexity was less than that of the following code's: r.get_tail<inherit_linearly<...>, i>::head_type::value OK, you're right, this also mentioned nothing about inherit_linearly, but I hope you can see how it would be easy to jump to this conclusion.
Second of all, by itself, of course the **result of invoking inherit_linearly** shown on that page is less capable than tuple, because there's no convenient access function like get<> provided.
Yes, but since the difficulty of element access is mentioned, and no easy solution provided, and since the book is about solution's provided by mpl, and since other book sections pose problems and then provide solutions, it's only natural for the reader to assume a solution is either impossible or very difficult; yet, get_ith_head_test.cpp demonstrates that it's neither. The only change involves using inherit_head_tail instead of inherit and defining get_ith_tail, which, as you say, is not particularly original; hence, the method used by get_ith_tail should be at least mentioned as a solution to the problem.
Finally, the kind of access being done is completely different from what's done with tuple.
I've not looked *real* close at tuple, but I assumed boost::tuple had the following type of access: tuple member function template, get<i>, provides access to the i-th value in an instance of tuple<T0,T1,...Tn> where i varies from 0..n-1. Likewise, tuple_type in test_instantiate in get_ith_head_test.cpp in sandbox/value has a very similar kind of access: tuple_type member function template, get_ith_head<i>, provides access to the i-th value in an instance of: reverse_fold < types , empty_base , inherit_head_tail<pexp<_2>,_1> > where types is some type sequence with type elements: T0,T1,...,Tn and pexp<_2> is some placeholder expression containing placeholder _2, where i varies from 0..n-1. Could you elaborate on how the kinds of element access in boost::tuple and that of tuple_type in get_ith_head_test.cpp are different?
I think I'll wait to see if anyone else is confused by this before worrying about it. :o)
OK.

On 01/16/2005 03:11 PM, Larry Evans wrote: [snip]
Second of all, by itself, of course the **result of invoking inherit_linearly** shown on that page is less capable than tuple, because there's no convenient access function like get<> provided.
Yes, but since the difficulty of element access is mentioned, and no easy solution provided, and since the book is about solution's provided by mpl, and since other book sections pose problems and then provide solutions, it's only natural for the reader to assume a solution is either impossible or very difficult; yet, get_ith_head_test.cpp demonstrates that it's neither. The only change involves using inherit_head_tail instead of inherit and defining get_ith_tail, which, as you say, is not particularly original; hence, the method used by get_ith_tail should be at least mentioned as a solution to the problem.
I apologize for that last sentence. It sounds imperative. I just should have said, "the reader would have expected a solution such as...". I should also admit that maybe my impressions were influenced by what I had been doing at the time, which involved the indexed_type's library. It provides a similar get element member function but uses a more direct method because the supertypes are all the same except for the index. I couldn't figure out a different method and when I read p. 191 I just got the impression that it wasn't possible, which obviously is not what the page says. I apologize for my tone and thanks to Aleksey and you for a great book. Regards, Larry

On 01/16/2005 03:11 PM, Larry Evans wrote:
On 01/15/2005 05:26 PM, David Abrahams wrote: [snip]
Finally, the kind of access being done is completely different from what's done with tuple.
I've not looked *real* close at tuple, but I assumed boost::tuple had the following type of access: [snip] Could you elaborate on how the kinds of element access in boost::tuple and that of tuple_type in get_ith_head_test.cpp are different?
Maybe you meant the way element access was being done. I've just looked at boost/tuple/detail/tuple_basic.hpp. I see two templates which may be candidates for how tuple implements get. The first is: template< int N > struct get_class { template<class RET, class HT, class TT > inline static RET get(const cons<HT, TT>& t) { #if BOOST_WORKAROUND(__IBMCPP__,==600) // vacpp 6.0 is not very consistent regarding the member template keyword // Here it generates an error when the template keyword is used. return get_class<N-1>::get<RET>(t.tail); #else return get_class<N-1>::BOOST_NESTED_TEMPLATE get<RET>(t.tail); #endif } ... and the 2nd, which looks closer to what could be the implementation is prefixed with comment: // -cons type accessors ---------------------------------------- // typename tuples::element<N,T>::type gets the type of the // Nth element ot T, first element is at index 0 // ------------------------------------------------------- but the code for that looks very similar to get_ith_tail. The difference is that get_ith_tail uses specialization to split apart the Head and Tail parts and recurses on the Tail, whereas tuples:element uses the nested typedef for tail_type to recurse on the tail. Do you mean this is completely different, or is there some other code I should look at to see how tuple accesses its elements?

Larry Evans <cppljevans@cox-internet.com> writes:
But the aforementioned
t.get_inherit_side<...>:::type::left_type::value;
does compile? OK, now I see. Instead of >::head_type, there should have been >::type::head_type. Does it make sense now?
Nope. I'm still looking for a member whose name is get_tail<...> and not seeing any such thing.
After all, it's no different than:
t.super_type_expr::member_var_name;
for some super_type_expr which access's some super_type of t and where member_var_name is some member variable defined in that super_type.
Oh, get_tail<...> was a base class of typeof(r)? If so, I missed that possibility. C++ syntax is weird.
Could you elaborate on how the kinds of element access in boost::tuple and that of tuple_type in get_ith_head_test.cpp are different?
As I wrote earlier, "the code in the book is looking up a member by its type, not by its index." -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

On 01/17/2005 07:35 PM, David Abrahams wrote:
Larry Evans <cppljevans@cox-internet.com> writes:
But the aforementioned
t.get_inherit_side<...>:::type::left_type::value;
does compile? OK, now I see. Instead of >::head_type, there should have been >::type::head_type. Does it make sense now?
Nope. I'm still looking for a member whose name is get_tail<...> and not seeing any such thing.
The lastest upload, get_ith_head_test.cpp has a member function, get_ith_head, which does this. The code: t.get_inherit_side<...>:::type::left_type::value; is simply a qualified access to the member variable of a supertype of t. There's no need for a member method, and all get_ith_head does is simply use what amounts to the above code to access the proper superclass member variable. As mentioned previously, this is no different than: t.sk::sk+1::sn::value; where t is of type T, and: s0 is supertype of T s1 is supertype of s0 ... sk is supertype of sk-1 ... sn is supertype of sn-1 and all get_tail<T,Index> (and it's successor, get_ith_tail) does is create a typedef for the Index-th supertype of T. There's obviously a 1-to-1 mapping between the values and qualifiers: sk::sk+1::...::sn where: for k in 0..n hence, there's no problem with having the same member variable name since it's prefixed by it's unique qualifier. Isn't this what tuple_base.hpp's element template does, except it just keeps following the tail_type typedefs for k times?

On 01/17/2005 09:32 PM, Larry Evans wrote: [snip]
name since it's prefixed by it's unique qualifier. Isn't this what tuple_base.hpp's element template does, except it just keeps following the tail_type typedefs for k times?
And element<N,T> defines the nested type for each value of N instead of just when N==0. IOW, it doesn't use "metafunction forwarding" defined on p. 57 of your and Aleksey's book.

On 01/17/2005 09:32 PM, Larry Evans wrote: [snip]
The code:
t.get_inherit_side<...>:::type::left_type::value;
is simply a qualified access to the member variable of a supertype of t. There's no need for a member method, and all get_ith_head does is simply use what amounts to the above code to access the proper superclass member variable. As mentioned previously, this is no different than:
t.sk::sk+1::sn::value;
I smell something wrong with the expression: t.sk::sk+1::sn::value; I can't put my finger on it, but it just seems suspicious.
participants (2)
-
David Abrahams
-
Larry Evans