
Hi everybody, Please find at http://groups.yahoo.com/group/boost/files/typeof.zip (and in the Spirit repository, TYPEOF_DEV branch) a new version of my typeof emulation library. This version has the documentation, as well as support for the following has been added: - arrays; - function pointers; - pointers to member functions; - pointers to data members. Any comments are welcome. I would also again greatly appreciate if anybody could try to compile the test with any compiler except VC7.1 (which I have), GCC and Metrowerks (which have native typeof support), or any compiler that does not support partial template specialization (which would not compile this anyway). Best regards, Arkadiy

Hi everybody,
Please find at http://groups.yahoo.com/group/boost/files/typeof.zip (and in the Spirit repository, TYPEOF_DEV branch) a new version of my typeof emulation library.
This version has the documentation, as well as support for the following has been added:
- arrays; - function pointers; - pointers to member functions; - pointers to data members.
Any comments are welcome. I would also again greatly appreciate if anybody could try to compile the test with any compiler except VC7.1 (which I have), GCC and Metrowerks (which have native typeof support), or any compiler
"Arkadiy Vertleyb" <vertleyb@hotmail.com> wrote that
does not support partial template specialization (which would not compile this anyway).
Have tested and works ok (VC7.1 though). Any chance to make it so it automagically registers types in its database as user uses the mechanism in code, rather than user having to do so manually. Other problem is that each "client" should really have a GUID. Any ideas on how that would work? regards Andy Little

"Andy Little" <andy@servocomm.freeserve.co.uk> wrote
Any chance to make it so it automagically registers types in its database as user uses the mechanism in code, rather than user having to do so manually. Other problem is that each "client" should really have a GUID. Any ideas on how that would work?
We have to tell the compiler about types/templates (whether it's done by the library itself or it's user -- is a different story). Therefore some kind of registration looks inavoidable. When I first posted this (a couple of months ago) I was trying to generate IDs automatically. Initially I used the MS-specific __COUNTER__ macro, then I switched to the method suggested by Paul Mensonides -- slightly less elegant, but much more portable. It turned out, however, that both these methods have the same problem -- they do not preserve IDs between compilation units, and therefore eventially leed to the ODR violation. I tried to work this around by using anonimous namespaces, but then David Abrahams proved that the ODR violation would still present in certain usage contexts. So I gave up, and started using manually-supplies IDs. I do realize that this is a significant inconvenience. Please note, however, that the IDs are specified on per-file rather than per-class basis (I use __LINE__ to distinguish inside one file). If we consider usage patterns of this facility, in many cases 3 parties are present: - the typeof library; - some other library (user library) that uses expression templates techniques (such as Spirit, Lambda, etc.); - the end user. In this case, the user library can register it's own classes. The end user than could just use the typeof for all the expressions geherated by this library, and would not have to worry about registration. In other words, the library authors could achieve the effect of typeof enabled for their library (I did this for Spirit -- can be found in the spirit repository in the TYPEOF_DEV branch). Of course, this assumes the best-case scenario, where no user-defined classes are used. When they are, they should still be registered by the end user. I am extremely interested in any strategies of generating IDs. GUID would be excelent, but, unfortunately, this is not an integer (can't be passed through sizeof). My current understanding -- the libraries should register their types against some undefined symbols which would be resolved by the end-user in the system-wide enum, so that different libraries can co-exist, something like this: enum { SPIRIT_REGISTRATION_GROUP = BOOST_TYPEOF_USER_GROUP, LAMBDA_REGISTRATION_GROUP, MY_GROUP1, MY_GROUP2, ... }; Regards, Arkadiy

"Arkadiy Vertleyb" <vertleyb@hotmail.com> writes:
It turned out, however, that both these methods have the same problem -- they do not preserve IDs between compilation units, and therefore eventially leed to the ODR violation. I tried to work this around by using anonimous namespaces, but then David Abrahams proved that the ODR violation would still present in certain usage contexts.
So I gave up, and started using manually-supplies IDs. I do realize that this is a significant inconvenience. Please note, however, that the IDs are specified on per-file rather than per-class basis (I use __LINE__ to distinguish inside one file).
I'm not convinced that this particular ODR violation ends up being a problem in practice, though -- ultimately we end up getting the same type out of any typeof(...), and if we're never generating linker symbols within the computation performed by typeof, we're probably going to get away with it. I think it's worth trying an automatic scheme and stress-testing it to see if we can make it break. Better yet, explicitly construct a pared-down version _designed_ to break and see if we can cause a problem. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

On Jul 10, 2004, at 8:53 AM, David Abrahams wrote:
"Arkadiy Vertleyb" <vertleyb@hotmail.com> writes:
I'm not convinced that this particular ODR violation ends up being a problem in practice, though -- ultimately we end up getting the same type out of any typeof(...), and if we're never generating linker symbols within the computation performed by typeof, we're probably going to get away with it. I think it's worth trying an automatic scheme and stress-testing it to see if we can make it break. Better yet, explicitly construct a pared-down version _designed_ to break and see if we can cause a problem.
The only time I've ever seen a compiler/toolchain diagnose an ODR violation is when it results in two symbols with the same name and different sizes being linked together. As you said, we're not generating anything for the linker so this case won't crop up. Fear, Uncertainty, and Doubt make me wonder if trying to use Arkadiy's typeof in an exported template would trigger an ODR violation diagnostic in an EDG compiler, but I have neither proof nor the compiler around. I say we try to get away with the ODR violation. We know we're getting typeof/decltype eventually, so the ODR violation will eventually disappear anyway. Doug

Doug Gregor <dgregor@cs.indiana.edu> writes:
"Arkadiy Vertleyb" <vertleyb@hotmail.com> writes:
I'm not convinced that this particular ODR violation ends up being a problem in practice, though -- ultimately we end up getting the same type out of any typeof(...), and if we're never generating linker symbols within the computation performed by typeof, we're probably going to get away with it. I think it's worth trying an automatic scheme and stress-testing it to see if we can make it break. Better yet, explicitly construct a pared-down version _designed_ to break and see if we can cause a problem.
The only time I've ever seen a compiler/toolchain diagnose an ODR violation is when it results in two symbols with the same name and different sizes being linked together.
Well, it's the *un-* diagnosed ODR violations that are really dangerous...
As you said, we're not generating anything for the linker so this case won't crop up. Fear, Uncertainty, and Doubt make me wonder if trying to use Arkadiy's typeof in an exported template would trigger an ODR violation diagnostic in an EDG compiler, but I have neither proof nor the compiler around.
I say we try to get away with the ODR violation. We know we're getting typeof/decltype eventually, so the ODR violation will eventually disappear anyway.
...but I agree with you anyway. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

"David Abrahams" <dave@boost-consulting.com> wrote
Well, it's the *un-* diagnosed ODR violations that are really dangerous...
When I was experimenting with this, as we discussed this topic during my initial submission, I was able to achieve the effect of calling different function by debug and release versions, probably because of inlining, by VC7.1 (although it was not related to the typeof). Scary... On the other hand, automatic registration can make it attractive to use the library in many cases where it is currently not. Do you think it's possible to create a test case that would test this more or less fully? Arkadiy

"David Abrahams" <dave@boost-consulting.com> wrote
Doug Gregor <dgregor@cs.indiana.edu> writes:
I say we try to get away with the ODR violation. We know we're getting typeof/decltype eventually, so the ODR violation will eventually disappear anyway.
...but I agree with you anyway.
So, it seems we all have some doubts, but still want to switch back to automatic ID generation... Anybody has any particular concernes about this? Arkadiy

David Abrahams wrote:
I'm not convinced that this particular ODR violation ends up being a problem in practice, though -- ultimately we end up getting the same type out of any typeof(...), and if we're never generating linker symbols within the computation performed by typeof, we're probably going to get away with it. I think it's worth trying an automatic scheme and stress-testing it to see if we can make it break. Better yet, explicitly construct a pared-down version _designed_ to break and see if we can cause a problem.
Just to understand you correctly: When I used typeof() in my constant library, I was told that it is not acceptable because it's not yet standard. Although both the EDG-based compiler I used (Intel) and the GCC offered __typeof__. Now people are trying to emulate the functionality of typeof. They want users to register their types and the library is still not as capable as a native typeof. Try the examples I provided for unit-library-compatible constants. And now you even say that it's OK to violate existing language rules on purpose just because you think it will likely work in practice? Sorry I don't get this. If violating the existing standard is an option, than __typeof__ should be an option as well. My 2¢. Regards, Daniel -- Daniel Frey aixigo AG - financial solutions & technology Schloß-Rahe-Straße 15, 52072 Aachen, Germany fon: +49 (0)241 936737-42, fax: +49 (0)241 936737-99 eMail: daniel.frey@aixigo.de, web: http://www.aixigo.de

Daniel Frey <daniel.frey@aixigo.de> writes:
David Abrahams wrote:
I'm not convinced that this particular ODR violation ends up being a problem in practice, though -- ultimately we end up getting the same type out of any typeof(...), and if we're never generating linker symbols within the computation performed by typeof, we're probably going to get away with it. I think it's worth trying an automatic scheme and stress-testing it to see if we can make it break. Better yet, explicitly construct a pared-down version _designed_ to break and see if we can cause a problem.
Just to understand you correctly: When I used typeof() in my constant library, I was told that it is not acceptable because it's not yet standard. Although both the EDG-based compiler I used (Intel) and the GCC offered __typeof__.
Perhaps you could post links to specific messages so we can see exactly what was said? If you're talking about http://lists.boost.org/MailArchives/boost/msg59186.php, "it's not acceptable because it's not standard" is not an accurate paraphrase of the message there.
Now people are trying to emulate the functionality of typeof. They want users to register their types and the library is still not as capable as a native typeof. Try the examples I provided for unit-library-compatible constants.
Perhaps you could post links to specific messages?
And now you even say that it's OK to violate existing language rules on purpose just because you think it will likely work in practice?
As an experiment, to see how portable it actually is... and only because we expect to see full language support soon.
Sorry I don't get this. If violating the existing standard is an option, than __typeof__ should be an option as well. My 2¢.
IMO __typeof__ is an option as long as there's a fallback for compilers that don't support it. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

David Abrahams wrote:
Daniel Frey <daniel.frey@aixigo.de> writes:
David Abrahams wrote:
I'm not convinced that this particular ODR violation ends up being a problem in practice, though -- ultimately we end up getting the same type out of any typeof(...), and if we're never generating linker symbols within the computation performed by typeof, we're probably going to get away with it. I think it's worth trying an automatic scheme and stress-testing it to see if we can make it break. Better yet, explicitly construct a pared-down version _designed_ to break and see if we can cause a problem.
Just to understand you correctly: When I used typeof() in my constant library, I was told that it is not acceptable because it's not yet standard. Although both the EDG-based compiler I used (Intel) and the GCC offered __typeof__.
Perhaps you could post links to specific messages so we can see exactly what was said?
If you're talking about http://lists.boost.org/MailArchives/boost/msg59186.php, "it's not acceptable because it's not standard" is not an accurate paraphrase of the message there.
This is the message I was talking about. And to me it means, that __typeof__ is not acceptable because it's not standard. Maybe I don't understand the message? The library needs some way to find out the type of an expression, __typeof__ works today for some compilers, in the future, we might have something like decltype and we can switch to it once it becomes available. Even if it's not compatible with __typeof__ directly, I'm sure it will provide the functionality needed. The details might differ, but I would be more than surprised to find out that decltype would not provide what is needed. So doesn't this mean that I can't use __typeof__? Maybe you refer to the fact that the message suggests that all I need is an appropriate fallback, but this depends on whether or not such a fallback is available. AFAICT, no proposed typeof-emulation was able to work for the unit-library examples I've shown, but maybe I haven't tried hard enough. But given that nothing worked for me, the conclusion for me is, that I can't use typeof because it (or decltype) is not (yet) standard.
Now people are trying to emulate the functionality of typeof. They want users to register their types and the library is still not as capable as a native typeof. Try the examples I provided for unit-library-compatible constants.
Perhaps you could post links to specific messages?
Hm, sorry, this is my fault. I think I haven't posted an analysis *why* all approaches of typeof-emulation won't do for the constant library. I just thought about these things, taking into account the examples for unit-libraries, and decided it won't work. The reason is, that the author of the constant library (or the constants) cannot know which unit-libraries are to be supported, and the author of the unit-library doesn't want to register stuff for a specific constant library. Dependencies. The problem is, that you have to register operators for pairs of arguments, one from the unit library, the other from the constant-library. Who is supposed to do that? But I also remember that this was a problem anyway, as -depending on the design of the unit-library- it sometimes worked out-of-the-box, sometimes it didn't. I guess I will have to work this out more detailed, but currently, I don't have time for it...
And now you even say that it's OK to violate existing language rules on purpose just because you think it will likely work in practice?
As an experiment, to see how portable it actually is... and only because we expect to see full language support soon.
Oh, I missed the "full language support soon"-part. Again, sorry.
IMO __typeof__ is an option as long as there's a fallback for compilers that don't support it.
As an alternative: Would a limited functionality be OK, too? In my case, meaning you can use the constant library with all types that have the same result type for operators as their arguments, e.g. T+T gives you a T, etc. This doesn't hold for unit-types, where we need typeof instead of the simple assumption above, but it still provides lots of useful functionality for "normal" types. Regards, Daniel -- Daniel Frey aixigo AG - financial solutions & technology Schloß-Rahe-Straße 15, 52072 Aachen, Germany fon: +49 (0)241 936737-42, fax: +49 (0)241 936737-99 eMail: daniel.frey@aixigo.de, web: http://www.aixigo.de

"Daniel Frey" <daniel.frey@aixigo.de> wrote
The reason is, that the author of the constant library (or the constants) cannot know which unit-libraries are to be supported, and the author of the unit-library doesn't want to register stuff for a specific constant library. Dependencies. The problem is, that you have to register operators for pairs of arguments, one from the unit library, the other from the constant-library. Who is supposed to do that?
Perhaps I could take a closer look at this (if you help me, of course) at some point, but in short, the author of constant library registers constants, and the author of unit library registers units, and whoever writes operators registers them with no respect to units or constants. How this all gets resolved in terms of IDs is another story. If we assign IDs automatically, the only problem we have is a possible ODR violation. If we don't want this, the libraries may register against undefined symbolic constants, and the end-user could resolve this in a system-wide enum. This is feasible because an ID is assigned on per-file basis, not per-class. Inside the file I distinguish by __LINE__. So there most likely would be one constant per library, and the end-user would do something like this: --- MyGroups.hpp: enum { UNIT_LIBRARY_GROUP = BOOST_TYPEOF_USER_GROUP, CONSTANT_LIBRARY_GROUP, OPERATOR_GROUP }; --- #include "MyGroups.hpp" #include <boost/unit_registration.hpp> #include <boost/constant_registration.hpp> #include <boost/operator_registration.hpp> // use BOOST_TYPEOF and BOOST_AUTO Arkadiy

Daniel Frey <daniel.frey@aixigo.de> writes:
Hm, sorry, this is my fault. I think I haven't posted an analysis *why* all approaches of typeof-emulation won't do for the constant library. I just thought about these things, taking into account the examples for unit-libraries, and decided it won't work. The reason is, that the author of the constant library (or the constants) cannot know which unit-libraries are to be supported, and the author of the unit-library doesn't want to register stuff for a specific constant library. Dependencies. The problem is, that you have to register operators for pairs of arguments, one from the unit library, the other from the constant-library.
I'm don't see why you'd need to register operators. If I'm not mistaken, with Arkadiy's solution you only need to register user-defined types and templates (and maybe functions if they are used as template arguments).
Who is supposed to do that? But I also remember that this was a problem anyway, as -depending on the design of the unit-library- it sometimes worked out-of-the-box, sometimes it didn't. I guess I will have to work this out more detailed, but currently, I don't have time for it...
And now you even say that it's OK to violate existing language rules on purpose just because you think it will likely work in practice? As an experiment, to see how portable it actually is... and only because we expect to see full language support soon.
Oh, I missed the "full language support soon"-part. Again, sorry.
IMO __typeof__ is an option as long as there's a fallback for compilers that don't support it.
As an alternative: Would a limited functionality be OK, too? In my case, meaning you can use the constant library with all types that have the same result type for operators as their arguments, e.g. T+T gives you a T, etc.
It seems reasonable that a library acquires added features on compilers where language extensions are available.
This doesn't hold for unit-types, where we need typeof instead of the simple assumption above, but it still provides lots of useful functionality for "normal" types.
Seems OK to me, in principle. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

"David Abrahams" <dave@boost-consulting.com> wrote
I'm don't see why you'd need to register operators. If I'm not mistaken, with Arkadiy's solution you only need to register user-defined types and templates (and maybe functions if they are used as template arguments).
Functions (as well as member functions and data members) are supported by the typeof library -- you don't need to register them. This comes from the fact that, for example, R(*)(T0, T1) can be applied to any function that matches this signature, and only depends on R, T0, and T1. So, as long as you register MyType, the following, for example, will be handled: int (MyType::*)(short&, const MyType&) const //FWIW Arkadiy

"Arkadiy Vertleyb" <vertleyb@hotmail.com> writes:
"David Abrahams" <dave@boost-consulting.com> wrote
I'm don't see why you'd need to register operators. If I'm not mistaken, with Arkadiy's solution you only need to register user-defined types and templates (and maybe functions if they are used as template arguments).
Functions (as well as member functions and data members) are supported by the typeof library -- you don't need to register them. This comes from the fact that, for example, R(*)(T0, T1) can be applied to any function that matches this signature, and only depends on R, T0, and T1.
So, as long as you register MyType, the following, for example, will be handled:
int (MyType::*)(short&, const MyType&) const //FWIW
It's clearly not a complete solution, then: template <int (*)()> struct f {}; int g(); int h(); BOOST_STATIC_ASSERT((!boost::is_same<typeof(f<&g>()),typeof(f<&h>()))); That's all I meant about registering functions. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

"David Abrahams" <dave@boost-consulting.com> wrote
"Arkadiy Vertleyb" <vertleyb@hotmail.com> writes:
Functions (as well as member functions and data members) are supported by the typeof library -- you don't need to register them. This comes from the fact that, for example, R(*)(T0, T1) can be applied to any function that matches this signature, and only depends on R, T0, and T1.
So, as long as you register MyType, the following, for example, will be handled:
int (MyType::*)(short&, const MyType&) const //FWIW
It's clearly not a complete solution, then:
template <int (*)()> struct f {};
int g(); int h();
BOOST_STATIC_ASSERT((!boost::is_same<typeof(f<&g>()),typeof(f<&h>())));
That's all I meant about registering functions.
Sorry, I misunderstood this. I don't have direct support for function pointer template parameters. As well as I don't have direct support for integral template parameters in general. It just would be infeasible for me to define all possible generic combinations, like: template<class, class, class> class foo1{}; template<class, int, int> class foo2{}; template<class, bool, int(*)()> class foo3{}; etc. Specialisations for these kind of templates need to be provided by hand. Or, better yet, such template parameters could be wrapped into mpl::int_, mpl::bool_, etc. I don't know if there is anything like this for a function pointer, but it definitely can be provided... Arkadiy

"Daniel Frey" <daniel.frey@aixigo.de> wrote
Now people are trying to emulate the functionality of typeof. They want users to register their types and the library is still not as capable as a native typeof.
I totally agree with this, except native typeof is not available on most compilers. Considering the fact that companies tend to stick with compilers (like many still use VC6 -- believe it or not), the native typeof is not going to be available to most people for a few more years after the typeof is in the Standard. Are we willing to wait 3 - 5 years? Regards, Arkadiy

Arkadiy Vertleyb wrote:
Any comments are welcome. I would also again greatly appreciate if anybody could try to compile the test with any compiler except VC7.1 (which I have), GCC and Metrowerks (which have native typeof support), or any compiler that does not support partial template specialization (which would not compile this anyway).
My attempt to compile ./libs/typeof/test/main.cpp failed so I quickly typed my small test (attached). Intel compiler compiled it. Wow! Great job, Arkadiy! [alnsn@x1000 test]$ icc -V Intel(R) C++ Compiler for 32-bit applications, Version 8.0 Build 20031016Z Package ID: l_cc_p_8.0.055 Copyright (C) 1985-2003 Intel Corporation. All rights reserved. FOR NON-COMMERCIAL USE ONLY -- Alexander Nasonov

Alexander Nasonov <alnsn@yandex.ru> wrote
My attempt to compile ./libs/typeof/test/main.cpp failed...
Could you tell me what exactly the Intel compiler complained about?
so I quickly typed my small test (attached). Intel compiler compiled it.
I am curious how it knew about std::string and vector. They are not supposed to be registered by the basic typeof facility. Are you sure you didn't #include anything else? Arkadiy

Arkadiy Vertleyb wrote:
Alexander Nasonov <alnsn@yandex.ru> wrote
My attempt to compile ./libs/typeof/test/main.cpp failed...
Could you tell me what exactly the Intel compiler complained about?
so I quickly typed my small test (attached). Intel compiler compiled it.
I am curious how it knew about std::string and vector. They are not supposed to be registered by the basic typeof facility. Are you sure you didn't #include anything else? It's a magic. I've just tried icc -E to see preprocessed output and I see typeof keyword there. Looks like either __MWERKS__ or __GNUC__ is defined. Can you switch to boost scheme of detecting the compiler? -- Alexander Nasonov

Alexander Nasonov <alnsn@yandex.ru> wrote
Can you switch to boost scheme of detecting the compiler?
Done. http://groups.yahoo.com/group/boost/files/typeof.zip The best I could do non-intruisively to Boost was to repeat the switch defined in "select_compiler_config.hpp"... Or can I do any better? Arkadiy

Arkadiy Vertleyb wrote:
Alexander Nasonov <alnsn@yandex.ru> wrote
Can you switch to boost scheme of detecting the compiler?
Done.
http://groups.yahoo.com/group/boost/files/typeof.zip
The best I could do non-intruisively to Boost was to repeat the switch defined in "select_compiler_config.hpp"... Or can I do any better?
Read $BOOST_ROOT/libs/config/config.htm. There you'll find BOOST_INTEL and BOOST_MSVC but I'm not sure it's a proper way either. You can also read "Guidelines for Boost Authors" section. -- Alexander Nasonov

Alexander Nasonov <alnsn@yandex.ru> wrote
My attempt to compile ./libs/typeof/test/main.cpp failed...
Could you tell me what exactly the Intel compiler complained about? If you surround typename by comments at line 115 in register_functions.hpp
Arkadiy Vertleyb wrote: the compilation will stop only after #pragma message("compiling Modifiers example..."). -- Alexander Nasonov

Alexander Nasonov wrote:
Alexander Nasonov <alnsn@yandex.ru> wrote
My attempt to compile ./libs/typeof/test/main.cpp failed...
Could you tell me what exactly the Intel compiler complained about? If you surround typename by comments at line 115 in register_functions.hpp
Arkadiy Vertleyb wrote: the compilation will stop only after #pragma message("compiling Modifiers example..."). ... and only in there saying: ../../../boost/typeof/typeof.hpp(37): error: more than one partial specialization matches the template argument list of class "boost::type_of::encode_type_impl<boost::type_of::encode_type_impl<boost::type_of::detail::push_back<boost::type_of::detail::push_back<boost::mpl::vector0<boost::mpl::void_>, boost::mpl::int_<131093>>::type, boost::mpl::int_<458770>>::type, const int *const>::type, const int [20]>" "boost::type_of::encode_type_impl<V, const T>" "boost::type_of::encode_type_impl<V, T [N]>"
I'd suggest to use is_array in combination with mpl::if_: template<class V, class T> struct encode_type_impl; template<class V, class T> struct encode_type_impl_array; // HERE! template<class T, class Iter> struct decode_type_impl; template<class V, class T> struct encode_type : boost::mpl::if_< ::boost::is_array<T>, encode_type_impl_array<V, T>, // AND HERE! encode_type_impl<V, T> >::type {}; Of course, you have to append _array to appropriate specialization of encode_type_impl. -- Alexander Nasonov

... and only in there saying: ../../../boost/typeof/typeof.hpp(37): error: more than one partial specialization matches the template argument list of class "boost::type_of::encode_type_impl<boost::type_of::encode_type_impl<boost::ty
Alexander Nasonov wrote: pe_of::detail::push_back<boost::type_of::detail::push_back<boost::mpl::vecto r0<boost::mpl::void_>, boost::mpl::int_<131093>>::type, boost::mpl::int_<458770>>::type, const int *const>::type, const int [20]>"
"boost::type_of::encode_type_impl<V, const T>" "boost::type_of::encode_type_impl<V, T [N]>"
Hmmm, do you think this is a compiler bug or a standard behavior? const int[20] looks to me like an array of const integers, so I would definitely expect the second specialization envoked, but maybe it's also legal to view it something like a const integer that happens to be here 20 times? Do you think similar problems are possible in other contexts?
I'd suggest to use is_array in combination with mpl::if_:
template<class V, class T> struct encode_type_impl; template<class V, class T> struct encode_type_impl_array; // HERE! template<class T, class Iter> struct decode_type_impl;
template<class V, class T> struct encode_type : boost::mpl::if_< ::boost::is_array<T>, encode_type_impl_array<V, T>, // AND HERE! encode_type_impl<V, T> >::type {};
Of course, you have to append _array to appropriate specialization of encode_type_impl.
#ifdeffed, as a workaround for Intel? Otherwise it may significantly affect the compile time... Arkadiy

"Arkadiy Vertleyb" <vertleyb@hotmail.com> writes:
Alexander Nasonov wrote:
... and only in there saying: ../../../boost/typeof/typeof.hpp(37): error: more than one partial specialization matches the template argument list of class "boost::type_of::encode_type_impl<boost::type_of::encode_type_impl<boost::ty pe_of::detail::push_back<boost::type_of::detail::push_back<boost::mpl::vecto r0<boost::mpl::void_>, boost::mpl::int_<131093>>::type, boost::mpl::int_<458770>>::type, const int *const>::type, const int [20]>" "boost::type_of::encode_type_impl<V, const T>" "boost::type_of::encode_type_impl<V, T [N]>"
Hmmm, do you think this is a compiler bug or a standard behavior? const int[20] looks to me like an array of const integers, so I would definitely expect the second specialization envoked, but maybe it's also legal to view it something like a const integer that happens to be here 20 times? Do you think similar problems are possible in other contexts?
In the first specialization, T is int[20]. This is due to the strange way in which cv-qualification "commutes" with array bounds: typedef int a20[20]; typedef a20 const ca20i; // an const array of 20 ints typedef int const a20ci[20]; // an array of 20 const ints. template <class T> struct X; template <class T> struct X<T const> {}; // template <class T, int N> struct X<T[N]> {}; -- uncomment for ambiguity X<ca20i> a; // the same type X<a20ci> b; Here's how you check whether they're equally specialized: synthesize unique types and values for T and N in each specialization: template <class T> struct X<T const> {}; // T = struct Foo {}; template <class T, int N> struct X<T[N]> {}; // T = struct Bar {};, N = Q can "Foo const" match "T[N]"? No. can "Bar[Q]" match "T const"? No. Therefore: they're equally specialized. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

"David Abrahams" <dave@boost-consulting.com> wrote
In the first specialization, T is int[20]. This is due to the strange way in which cv-qualification "commutes" with array bounds:
typedef int a20[20]; typedef a20 const ca20i; // an const array of 20 ints
typedef int const a20ci[20]; // an array of 20 const ints. template <class T> struct X; template <class T> struct X<T const> {}; // template <class T, int N> struct X<T[N]> {}; -- uncomment for ambiguity X<ca20i> a; // the same type X<a20ci> b;
Or, in other words, by definition, "array of const/volatile T" is the same as "const/volatile array of T" (which basically causes the ambiguity)? This looks like unique quality of arrays and we should not run into it in any other contexts, should we?
Here's how you check whether they're equally specialized:
synthesize unique types and values for T and N in each specialization:
template <class T> struct X<T const> {}; // T = struct Foo {}; template <class T, int N> struct X<T[N]> {}; // T = struct Bar {};, N = Q
can "Foo const" match "T[N]"? No. can "Bar[Q]" match "T const"? No.
Therefore: they're equally specialized.
And the easiest way to resolve this particular case would be to provide the third specialization: template <class T, int N> struct X<const T[N]> {}; // T = struct Foo{};, N = Q To handle volatiles (I am not doing this right now), I would just have to add another two: template <class T, int N> struct X<volatile T[N]> {}; template <class T, int N> struct X<const volatile T[N]> {}; Am I getting this correctly? Arkadiy

Alexander Nasonov wrote:
I'd suggest to use is_array in combination with mpl::if_:
template<class V, class T> struct encode_type_impl; template<class V, class T> struct encode_type_impl_array; // HERE! template<class T, class Iter> struct decode_type_impl;
template<class V, class T> struct encode_type : boost::mpl::if_< ::boost::is_array<T>, encode_type_impl_array<V, T>, // AND HERE! encode_type_impl<V, T> >::type {};
Of course, you have to append _array to appropriate specialization of encode_type_impl.
This would definitely solve the problem but, as I said, I have concernes about the need to instantiate mpl::if_<> and is_array<> for every node in the expression. I think we can get away by just providing a more specialized case: boost::type_of::encode_type_impl<V, const T [N]>. http://groups.yahoo.com/group/boost/files/typeof.zip On VC7.1 it seems to work fine (as it was before, actually), but unfortunately I can't test this on Intel... Arkadiy

Arkadiy Vertleyb wrote:
This would definitely solve the problem but, as I said, I have concernes about the need to instantiate mpl::if_<> and is_array<> for every node in the expression. I think we can get away by just providing a more specialized case:
boost::type_of::encode_type_impl<V, const T [N]>.
http://groups.yahoo.com/group/boost/files/typeof.zip
On VC7.1 it seems to work fine (as it was before, actually), but unfortunately I can't test this on Intel...
If you change modifiers.hpp:110 from typedef typename const d::type type[n]; to typedef typename d::type const type[n]; and add using namespace std; to main.cpp (cout and endl are not always prefixed with std:: in your test) everything will compile on Intel C++. I also tried not to use native typeof under g++. Both 3.2.2 and 3.4.0 compile the test. BTW, I think it's good idea to add BOOST_NO_NATIVE_TYPEOF definition. BTW2, Intel 8.0 has also native typeof. -- Alexander Nasonov

On Jul 11, 2004, at 1:16 AM, <alnsn@yandex.ru> wrote:
Arkadiy Vertleyb wrote: compile the test. BTW, I think it's good idea to add BOOST_NO_NATIVE_TYPEOF definition.
We tend to use BOOST_NO_XXX to describe language/library features that should be there but aren't (or work improperly) and BOOST_HAS_XXX for extensions, so it would probably be best to call it BOOST_HAS_TYPEOF. Doug

Doug Gregor wrote:
On Jul 11, 2004, at 1:16 AM, <alnsn@yandex.ru> wrote:
Arkadiy Vertleyb wrote: compile the test. BTW, I think it's good idea to add BOOST_NO_NATIVE_TYPEOF definition.
We tend to use BOOST_NO_XXX to describe language/library features that should be there but aren't (or work improperly) [skiped]
Then I suspect we may need BOOST_NO_TYPEOF in a future. Let's reserve it now ;-) -- Alexander Nasonov

Alexander Nasonov <alnsn@yandex.ru> wrote
and add using namespace std; to main.cpp (cout and endl are not always prefixed with std:: in your test) everything will compile on Intel C++.
Great, thanks. I actually have no slightest idea why it compiles in VC7.1 without this "using" directive :)
I also tried not to use native typeof under g++. Both 3.2.2 and 3.4.0 compile the test.
Do you mean you forced it to use my encoding/decoding stuff? I tried this at some point with g++ 3.3, and got rather stupid complain, something like mpl::int_<n>::value being non-constant expression... I will try it once more...
BTW, I think it's good idea to add BOOST_NO_NATIVE_TYPEOF definition.
Do you mean in compiler_config.hpp, to easily distinguish between those compilers that have native typeof support and those that don't? In this case we have to be more specific, because, for example g++ uses "typeof" and Metrowerkes uses "__typeof__". Or do you mean forcing compilers to use encoding/decoding even if they do support typeof natively? In this case it is library-specific, and I would call it something like BOOST_TYPEOF_DISABLE_NATIVE_SUPPORT. Arkadiy

Arkadiy Vertleyb wrote:
Or do you mean forcing compilers to use encoding/decoding even if they do support typeof natively? In this case it is library-specific, and I would call it something like BOOST_TYPEOF_DISABLE_NATIVE_SUPPORT. or BOOST_FORCE_TYPEOF_EMULATION. -- Alexander Nasonov

Alexander Nasonov <alnsn@yandex.ru> wrote
or BOOST_FORCE_TYPEOF_EMULATION.
I don't have strong feelings about this, except I think this is a library-specific macro, and should be prefixed with the library name. So I made it BOOST_TYPEOF_FORCE_EMULATION, and fixed a couple of things, so that now the whole test does compile in g++ 3.3, something like this, from the test directory: g++ main.cpp -I<boost-dir> -I..\..\.. -DBOOST_TYPEOF_FORCE_EMULATION Of course, without the define, this also works (and much faster). If nothing else, it allows to test the stuff against one more compiler. http://groups.yahoo.com/group/boost/files/typeof.zip Arkadiy

Arkadiy, I put a reference to your library to Russian site www.rsdn.ru. Shortly after that Andrey Beliakov commented out sizer class. He writes that sizeof(sizer<N>) is not necessarily equal to N::value. Andrey suggests rewriting the sizer: template<class N> struct sizer { typedef char(&type)[N::value]; }; and use sizer<N>::type in place of sizer<N>. Here is a reference to his message (in Russian): http://www.rsdn.ru/Forum/Message.aspx?mid=717690&only=1 -- Alexander Nasonov

Alexander Nasonov <alnsn@yandex.ru> wrote
Arkadiy, I put a reference to your library to Russian site www.rsdn.ru. Shortly after that Andrey Beliakov commented out sizer class. He writes that sizeof(sizer<N>) is not necessarily equal to N::value. Andrey suggests rewriting the sizer:
template<class N> struct sizer { typedef char(&type)[N::value]; };
and use sizer<N>::type in place of sizer<N>.
Cool! The only reason I wrote sizer in the first place was because I wasn't able to return an array from the function. And it turns out all I had to do was to use a reference to array... I will probably eliminate this class, and use char(&)[n] directly. Arkadiy
participants (6)
-
alnsn@yandex.ru
-
Andy Little
-
Arkadiy Vertleyb
-
Daniel Frey
-
David Abrahams
-
Doug Gregor