
Hi all, A couple of questions regarding typeof: 1) Is it going to be in the next C++ standard? 2) Is there any estimate when it is going to happen? I assume that quite a few Boost libraries could largely benefit from this operator. Spirit documentation even contains a section on typeof and how the syntax could be improved with it. I recently had a need to determine a type of a Lambda functor (but got away with Boost.Function with some performance expences). Also Joaquin recently raised a similar question. Our RTL syntax would also benefit a lot if this facility was available. About one and a half year ago Steve Dewhurst published three articles on this subject in CUJ. The idea was to encode the type as an integer using bitwise operations. This integer could be than "returned" from the function, this crossing the boundaries between a type and a value, and then decoded into the original type. I wonder if this or any other technique is currently being considered by anyone to be added to Boost or we are just waiting until the real typeof is available? I have been experimenting with this, and came up with a very simple trick that allows to use a static list of integers, like mpl::vector_c, instead of bitwise operations, to encode the type, and pass this list across the function boundaries. I think, if nothing else, this is much simpler than bitwise operations. Everything else is pretty much like in Steve's approach. Based on this it seems to be pretty simple to encode/decode types to implement typeof-like facilities for some specific (or maybe not so specific) cases. Has anybody already done something similar, and/or is this of any interest? If there is an interest I am ready to provide explanation, code, etc. Regards, Arkadiy

On Apr 19, 2004, at 9:02 PM, Arkadiy Vertleyb wrote:
Hi all,
A couple of questions regarding typeof:
1) Is it going to be in the next C++ standard? 2) Is there any estimate when it is going to happen?
It seems likely that the answer to question 1 is yes. The answer to question 2 is, when the next C++ standard is released, which is still some years away. If all goes well it may be in the working draft in a year or so, but there are no guarantees. Here's the latest proposal, though there are changes to the specifications after this, and not all 'auto' features discussed are under consideration anymore. Also there are still some issues to be solved in the decltype specification too. So this just as a caveat, don't start to write your programs against this spec quite yet :) http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2004/n1067.pdf Best, Jaakko

If you want to play with it, gcc has some implementation of typeof. I don't know how complete it is, and last I tried it tended to crash gcc, probably because it hasn't had much testing.

I am interested in such a "typeof" mechanism. Would you like to provide some code and documentation, please? "Arkadiy Vertleyb" <vertleyb@hotmail.com> ÐŽÈëÓÊŒþ news:c62011$ag7$1@sea.gmane.org...
If there is an interest I am ready to provide explanation, code, etc.
Regards, Arkadiy

"Arkadiy Vertleyb" <vertleyb@hotmail.com> writes:
About one and a half year ago Steve Dewhurst published three articles on this subject in CUJ. The idea was to encode the type as an integer using bitwise operations. This integer could be than "returned" from the function, this crossing the boundaries between a type and a value, and then decoded into the original type.
That's the basic idea behind all typeof() emulations that I've ever seen. They all require some type registration to associate a compile-time integral constant with a type. The innovation that Steve brought, IIUC, was that with the registration of only class types, the rest of the transformations possible in the type system could be encoded by the library automatically. For example, if you register class Foo, then the library can generate encodings for Foo*, Foo[2], Foo**, int (Foo), Foo(*)(Foo,Foo), etc., so you don't have to register those types. The problem is that those numbers can get very large...
I wonder if this or any other technique is currently being considered by anyone to be added to Boost or we are just waiting until the real typeof is available?
I have been experimenting with this, and came up with a very simple trick that allows to use a static list of integers, like mpl::vector_c, instead of bitwise operations, to encode the type,
...so that you need multiple-precision integers to represent the values. What Steve did IIRC was to use array types, where each array bound encoded an additional base 2^32 "digit", so char[4][27] would endcode 3 * (2^32)^0 + 26 * (2^32)^1 I think I have that right ;-) My guess is that manipulating array types in that way has a lower cost at compile-time than using a vector_c, though using mpl probably yields much nicer library code and vector_c is more portable. You might look at this thread http://tinyurl.com/ytpfj ("typeof() substitute) to see how Aleksey quickly built a sequence iterator for array types. It might be interesting to get your typeof implementation together with what Joel describes in http://article.gmane.org/gmane.comp.lib.boost.devel/33942.
and pass this list across the function boundaries. I think, if nothing else, this is much simpler than bitwise operations. Everything else is pretty much like in Steve's approach. Based on this it seems to be pretty simple to encode/decode types to implement typeof-like facilities for some specific (or maybe not so specific) cases.
For what it's worth, I'm pretty sure I know how to solve the problem that most typeof() implementations strip top-level references. See boost/iterator/is_lvalue_iterator.hpp for a demonstration. Cheers, Dave -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

"David Abrahams" <dave@boost-consulting.com> wrote
That's the basic idea behind all typeof() emulations that I've ever seen. They all require some type registration to associate a compile-time integral constant with a type. The innovation that Steve brought, IIUC, was that with the registration of only class types, the rest of the transformations possible in the type system could be encoded by the library automatically. For example, if you register class Foo, then the library can generate encodings for Foo*, Foo[2], Foo**, int (Foo), Foo(*)(Foo,Foo), etc., so you don't have to register those types. The problem is that those numbers can get very large...
Right. What I am even more interested in, is the ability to generate encodings of complicated templates. Say I registered int, std::vector, and mpl::vector2, and the library should be able to work with std::vector<int>, mpl::vector2<std::vector<int>, mpl::vector2<int, int> >, etc. It looks like this can be solved pretty easily. I imagine that Boost.Lambda, for example might also benefit from the ability to encode/decode templates (and maybe Spirit, but I am not sure).
My guess is that manipulating array types in that way has a lower cost at compile-time than using a vector_c, though using mpl probably yields much nicer library code and vector_c is more portable.
I don't suspect my solution is very compile-time efficient. But I don't have enough knowledge of compilers internals to estimate this. I believe the real advantage is in is simplicity. Anyway, here it is... Let's recall that to achieve our goal we have to: 1) Pass our expression to a function template, like: template<class T> SOMETHING foo(const T&); 2) inside foo() encode our type into a compile-time list of integers; 3) somehow manage to pass this list through the function boundaries; 4) decode the type. The most chalanging is 3. Let's define the following template: template<class N> struct sizer { char_[N::value]; }; The whole purpose of this is to create classes with a given sizeof (to be completely accurate we have to then divide this by sizeof(char)). Next template is what it is all about: template<class IntList> struct multi_int { typedef IntList int_list; template<class T> sizer<typename mpl::apply_if< typename mpl::less<T, typename mpl::size<int_list>::type>, mpl::at<IntList, T>, mpl::identity<mpl::int_<1> > >::type> get(const T&); }; So, if we have an object of this class, x, then sizeof(x.get(mpl::int_<n>())) defines the nth element of the list, and out-of-range values produce 1. The list can be reproduced like, say: #define BOOST_RTL_TYPEITEM(Expr, N)\ mpl::int_<sizeof(Expr.get(mpl::int_<N>()))> mpl::vector<\ BOOST_RTL_TYPEITEM(x, 0) , BOOST_RTL_TYPEITEM(x, 1) ... , BOOST_RTL_TYPEITEM(x, N)
Where it can be generated by the preprocessor for a fairly large N. The reproduced list is larger than the original one, and is 1-padded. The encoding scheme I use does not require to know where the list ends, so this doesn't matter. This is basically it. The return type of the function foo above (sorry for such name) is going to be multi_int<encode<T>::type>, where T is the original type, and encode template works accordingly to some encoding scheme. The encoding scheme to choose is a separate issue. In my example I encode templates by adding the encodings of its parameters to the code of template itself. So, if int is 1, std::vector is 2, and mpl::vector2 is 3, the above example: mpl::vector2<std::vector<int>, mpl::vector2<int, int> > becomes 3 2 1 3 1 1 Also note that all templates with one parameter behave similarly, so only one registration macro is required. Another macro is required to register templates with two parameters, etc.
For what it's worth, I'm pretty sure I know how to solve the problem that most typeof() implementations strip top-level references. See boost/iterator/is_lvalue_iterator.hpp for a demonstration.
Cool. I imagine pointers are pretty easy, but references surely represent a big problem... I will follow up with the working sketch... Regards, Arkadiy
participants (5)
-
Allen Yao
-
Arkadiy Vertleyb
-
David Abrahams
-
Jaakko
-
Neal D. Becker