[Typeof] Formal Review in progress

Hi All, A reminder that the Typeof Formal Review is currently in progress and runs until May 30th. So far there have been only two reviews, both in favour of the library. (Thanks again to both those reviewers for their time and energy). Nevertheless it would be nice to get some more opinion, affirmation , etc regarding this important library. One area in particular that has been cited as worthy of improvement is the documentation, so please download the library and take a look at it. (And then write a review ;-) ) Are there enough examples? Is there enough information regarding how to use the library. Is it workable in a large project?. is the effect on compile time a problem.? etc. I'm sure that Arkadiy and Peder would welcome feedback on the documentation in particular so that they can improve it. So please try to find time to write a review. The proposed Typeof library emulates the functionality of the non-standard 'typeof' operator, and incomplete implementations of decltype and the proposed 'auto' declarator , described in http://www.osl.iu.edu/~jajarvi/publications/papers/decltype_n1478.pdf. It is commonly acknowledged that this type of functionality is sorely needed and should be standardardised in the language. For compliant compilers the library requires some help in the form of registration macros but, because use of typeof is by its nature most likely in generic libraries, it is expected that this can often be done by the library author rather than the user. In some cases the compilers capabilities (by means of extensions and even compiler bugs) have been used to remove the need for registration. However, for portability and in order to test emulation mode on the compilers where it is available but not used by default (VC7.1, GCC etc), #define BOOST_TYPEOF_COMPLIANT [see note *1*]. Testing the emulation is useful, even on compilers that provide a better option, to get a rounded view of the library and its capabilities. I hope you will find time to write a review of the library, which is available at: http://boost-sandbox.sourceforge.net/vault/ , typeof.zip The system has been tested with the following compilers: MSVC 6.5/7.0/7.1/8.0; [see note *1* regarding VC7.0 and VC6.5] GCC 3.4.2 (The following is a quote from : http://www.boost.org/more/formal_review_process.htm ) Here are some questions you might want to answer in your review: What is your evaluation of the design? What is your evaluation of the implementation? What is your evaluation of the documentation? What is your evaluation of the potential usefulness of the library? Did you try to use the library? With what compiler? Did you have any problems? How much effort did you put into your evaluation? A glance? A quick reading? In-depth study? Are you knowledgeable about the problem domain? And finally, every review should answer this question: Do you think the library should be accepted as a Boost library? Be sure to say this explicitly so that your other comments don't obscure your overall opinion. Andy Little Typeof review manager notes: *1* MSVC6.5 and VC7.0 are not supported by the BOOST_TYPEOF_COMPLIANT macro

My review was ready two days ago, I just couldn't post it. Sorry for delay. Andy Little <andy <at> servocomm.freeserve.co.uk> writes:
What is your evaluation of the design? What is your evaluation of the implementation?
I don't fully understand it so I can comment only few things. - Why decode_type_impl and encode_type_impl primary templates are declared in unnamed namespace? All specializations are also in (other) unnamed namespaces. Is it intentional? - It would be nice to put some functionality like get_unsigned<T> in correspondent libraries. This way, we could have better support for them. In this particular case, non-standard integral types could be supported as well. See also my note about documentation. - encode_integral casts integral type to size_t. Is there any guarantee that size_t is always big enough? - I don't understand why some big contants are hardcoded? For example, encode_size_t template checks if n >= 0x3fffffff. If it's magic, can you please comment it explicitly?
What is your evaluation of the documentation?
Not yet complete. - There's no references to online versions of Steve Dewhurst's articles. They can be found at http://www.semantics.org/localarchive.html - No information at all about how to compile in compliant mode. - Why only "well-known integral type" are registered implicitly? I think that all integral types supported by boost::is_integral should be supported by the library as well.
What is your evaluation of the potential usefulness of the library? Very useful
Did you try to use the library? With what compiler? Did you have any problems? I've tried gcc 3.2 in both native and compliant modes. It works fine. Free version of Intel 8.0 under linux compiles in native mode. Linux version of this compiler comes with gcc emulation mode and, AFAIK, __typeof__ is also emulated. Though, I don't know whether it differs from gcc __typeof__. Intel compiler fails to compile in compliant mode because of bug in the compiler. BTW, who is a best person to send a bug report to Intel? Me or the authors?
How much effort did you put into your evaluation? A glance? A quick reading? In-depth study?
Somewhere between "A quick reading" and "In-depth study".
Are you knowledgeable about the problem domain?
I heard about typeof but I never read WG21 papers.
And finally, every review should answer this question:
Do you think the library should be accepted as a Boost library?
It should be accepted. -- Alexander Nasonov

Hi Sasha :) Thanks for this review (and also for pointing me to RSDN, and helping with Intel).
- Why decode_type_impl and encode_type_impl primary templates are declared in unnamed namespace? All specializations are also in (other) unnamed
Why "(other)"? I believe they are the same in the same TU...
namespaces. Is it intentional?
Yes. Automatic ID generation leads to potential ODR violation, since, depending on the order of inclusion, the same template specializations can be generated with different IDs, and therefore with different bodies. This was workarounded by placing them into anonimous namespaces, so that thay are different in different TU, and so not the subject to ODR. Unfortunately, this did not completely solve the problem -- it just moved it to a different place. Since BOOST_TYPEOF is now in anonimous namespace, it is different in different TU, and so itself technically causes ODR if used in the header files, pseudocode: TU1: struct A { type_of::anonimous-TU1::decode<>::type; }; TU2: struct A { type_of::anonimous-TU2::decode<>::type; // the same type, really, but computed differently }; This question was discussed in the past, and it was decided that we can live with this as long as we have a specific test that verifies that compilers don't really care. We have such test, and at some point Martin Wille helped me by running it on como, which is considered to be the most strict compiler. Of course it's also a part of our regular test.
- It would be nice to put some functionality like get_unsigned<T> in correspondent libraries. This way, we could have better support for them. In this particular case, non-standard integral types could be supported as well. See also my note about documentation.
- encode_integral casts integral type to size_t. Is there any guarantee that size_t is always big enough?
- I don't understand why some big contants are hardcoded? For example, encode_size_t template checks if n >= 0x3fffffff. If it's magic, can you please comment it explicitly?
Actually a stronger limitation is the size of the array that I use to create appropriate sizeof(). The magic constant above has to do with the fact that I use a couple of bits as flags, such as if there is an overflow, and decide whether to use the second integer for encoding. I agree that this is not portable as is to the 64 bit platforms, for example.
What is your evaluation of the documentation?
Not yet complete.
- There's no references to online versions of Steve Dewhurst's articles. They can be found at http://www.semantics.org/localarchive.html - No information at all about how to compile in compliant mode. - Why only "well-known integral type" are registered implicitly? I think that all integral types supported by boost::is_integral should be supported by the library as well.
OK. BTW, the library also has most Standard C++ Library types/templates registered, but for this some additional headers need to be included, such as: #include <boost/typeof/std/string.hpp> #include <boost/typeof/std/memory.hpp> etc. I don't know how noticable this is in the current doc, though.
Do you think the library should be accepted as a Boost library?
It should be accepted.
Thanks again. Regards, Arkadiy

Arkadiy Vertleyb writes:
Hi Sasha :)
Why "(other)"? I believe they are the same in the same TU...
Now I see. In 7.3.1.1: An unnamed namespace definition behaves as if it were replaced by namespace unique { /* empty body */ } using namespace unique; namespace unique { namespacebody } where all occurrences of *unique* in a translation unit are replaced by *the same identifier* and this identifier differs from all other identifiers in the entire program. Somehow I missed *the same identifier*. How could I ever program for years without knowing this?
namespaces. Is it intentional?
Yes.
Automatic ID generation leads to potential ODR violation, since, depending on the order of inclusion, the same template specializations can be generated with different IDs, and therefore with different bodies. This was workarounded by placing them into anonimous namespaces, so that thay are different in different TU, and so not the subject to ODR. [skiped] This question was discussed in the past, and it was decided that we can live with this as long as we have a specific test that verifies that compilers don't really care. We have such test, and at some point Martin Wille helped me by running it on como, which is considered to be the most strict compiler. Of course it's also a part of our regular test.
Yeah, I remember this discussion. One idea came to my mind. In order to avoid ODR violations, can we switch from definitions to declarations? Every BOOST_TYPEOF_REGISTER_TYPE macro could add overloaded reg_entry function which encodes a given type T: template<class T> char (& reg_entry(identity<T>) ) [CODE1][CODE2] ... [CODE50]; [skiped]
I don't know how noticable this is in the current doc, though.
I don't care much about a quality of documenation for now. Lack of it may be even better because it could protect from overusing the library. This reminds me of the fact that a first version of MPL was introduced inofficially. Thanks Arkadiy and Peder for great library! -- Alexander Nasonov

"Alexander Nasonov" <alnsn-boost@yandex.ru> wrote
One idea came to my mind. In order to avoid ODR violations, can we switch from definitions to declarations?
Every BOOST_TYPEOF_REGISTER_TYPE macro could add overloaded reg_entry function which encodes a given type T:
template<class T> char (& reg_entry(identity<T>) ) [CODE1][CODE2] ... [CODE50];
Not sure I understand this... Can you ellaborate? Regards, Arkadiy

"Arkadiy Vertleyb" <vertleyb@hotmail.com> writes:
"Alexander Nasonov" <alnsn-boost@yandex.ru> wrote
One idea came to my mind. In order to avoid ODR violations, can we switch from definitions to declarations?
Every BOOST_TYPEOF_REGISTER_TYPE macro could add overloaded reg_entry function which encodes a given type T:
template<class T> char (& reg_entry(identity<T>) ) [CODE1][CODE2] ... [CODE50];
Not sure I understand this... Can you ellaborate?
The function returns a reference to a multidimensional array, where each numerical element that you were putting in the mpl::vector is encoded as a separate dimension of the array. -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams writes:
The function returns a reference to a multidimensional array, where each numerical element that you were putting in the mpl::vector is encoded as a separate dimension of the array.
Exactly. It's the vector returned by encode_type_impl. I didn't have a chance to think about my idea thoroughly but this is something completely different. Partial specializations aren't supported by functions, for example. -- Alexander Nasonov

"Alexander Nasonov" <alnsn-boost@yandex.ru> wrote in message
David Abrahams writes:
The function returns a reference to a multidimensional array, where each numerical element that you were putting in the mpl::vector is encoded as a separate dimension of the array.
Exactly. It's the vector returned by encode_type_impl. I didn't have a chance to think about my idea thoroughly but this is something completely different. Partial specializations aren't supported by functions, for example.
I think they are: template<class T> char foo(vector<T>& v)[id1][id2][id3]; But how would this work? This array type will stay inside the function. We need a function to return the object of certain _size_ in order to pass it outside... Regards, Arkadiy

Arkadiy Vertleyb <vertleyb <at> hotmail.com> writes:
I think they are:
template<class T> char foo(vector<T>& v)[id1][id2][id3];
But how would this work? This array type will stay inside the function.
#include <boost/mpl/assert.hpp> #include <boost/mpl/equal.hpp> #include <boost/mpl/vector_c.hpp> char (&foo())[9][8][7][6]; int main() { using namespace boost::mpl; typedef vector_c< int , sizeof(foo()) / sizeof(foo()[0]) , sizeof(foo()[0]) / sizeof(foo()[0][0]) , sizeof(foo()[0][0]) / sizeof(foo()[0][0][0]) , sizeof(foo()[0][0][0]) / sizeof(foo()[0][0][0][0]) > vec; BOOST_MPL_ASSERT(( equal< vec, vector_c<int,9,8,7,6> > )); } Sizes may become very huge, though.
We need a function to return the object of certain _size_ in order to pass it outside...
I don't understand it. -- Alexander Nasonov

On 5/27/05, Alexander Nasonov <alnsn-boost@yandex.ru> wrote:
Arkadiy Vertleyb <vertleyb <at> hotmail.com> writes:
I think they are:
template<class T> char foo(vector<T>& v)[id1][id2][id3];
But how would this work? This array type will stay inside the function.
#include <boost/mpl/assert.hpp> #include <boost/mpl/equal.hpp> #include <boost/mpl/vector_c.hpp>
char (&foo())[9][8][7][6];
int main() { using namespace boost::mpl;
typedef vector_c< int , sizeof(foo()) / sizeof(foo()[0]) , sizeof(foo()[0]) / sizeof(foo()[0][0]) , sizeof(foo()[0][0]) / sizeof(foo()[0][0][0]) , sizeof(foo()[0][0][0]) / sizeof(foo()[0][0][0][0]) > vec;
BOOST_MPL_ASSERT(( equal< vec, vector_c<int,9,8,7,6> > )); }
Sizes may become very huge, though.
If you replace your function with: char (&foo())[900][800][700][600]; you will get an overflow when calculating e.g. sizeof(foo()) / sizeof(foo()[0]), and the result will be garbage.
We need a function to return the object of certain _size_ in order to pass it outside...
I don't understand it.
-- Alexander Nasonov
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Peder Holt <peder.holt <at> gmail.com> writes:
On 5/27/05, Alexander Nasonov <alnsn-boost <at> yandex.ru> wrote:
Sizes may become very huge, though.
If you replace your function with: char (&foo())[900][800][700][600]; you will get an overflow when calculating e.g. sizeof(foo()) / sizeof(foo()[0]), and the result will be garbage.
That's right. Huge arrays can be replaced with tuples. tuple<char(&)[9], char(&)[8], char(&)[7], char(&)[6]> foo(); sizeof(get<0>(foo())); sizeof(get<1>(foo())); sizeof(get<2>(foo())); sizeof(get<3>(foo())); Not sure if it compiles with boost::tuple. -- Alexander Nasonov

"Alexander Nasonov" <alnsn-boost@yandex.ru> wrote
sizeof(get<0>(foo())); sizeof(get<1>(foo())); sizeof(get<2>(foo())); sizeof(get<3>(foo()));
Interesting :-) This is very close to the technique I originally used, before deciding to pass the position directly into foo(), and renaming it with "at()". Regards, Arkadiy

Alexander Nasonov <alnsn-boost@yandex.ru> writes:
Peder Holt <peder.holt <at> gmail.com> writes:
On 5/27/05, Alexander Nasonov <alnsn-boost <at> yandex.ru> wrote:
Sizes may become very huge, though.
If you replace your function with: char (&foo())[900][800][700][600]; you will get an overflow when calculating e.g. sizeof(foo()) / sizeof(foo()[0]), and the result will be garbage.
That's right. Huge arrays can be replaced with tuples.
tuple<char(&)[9], char(&)[8], char(&)[7], char(&)[6]> foo();
Why not an mpl::vector for that matter? It's easy enough to extract each dimension of an array with partial specialization. Just do the representation backwards: char (& foo( whatever ) ) [CODEN][CODEN-1]...[CODE1][CODE0] Steve Dewhurst was here before us.
sizeof(get<0>(foo())); sizeof(get<1>(foo())); sizeof(get<2>(foo())); sizeof(get<3>(foo()));
Not sure if it compiles with boost::tuple.
Inefficient at compile time. get<N> is O(N) each time, thus the above is O(N^2); that's part of what's behind the fusion library. -- Dave Abrahams Boost Consulting www.boost-consulting.com

On 5/27/05, David Abrahams <dave@boost-consulting.com> wrote:
Alexander Nasonov <alnsn-boost@yandex.ru> writes:
Peder Holt <peder.holt <at> gmail.com> writes:
On 5/27/05, Alexander Nasonov <alnsn-boost <at> yandex.ru> wrote:
Sizes may become very huge, though.
If you replace your function with: char (&foo())[900][800][700][600]; you will get an overflow when calculating e.g. sizeof(foo()) / sizeof(foo()[0]), and the result will be garbage.
That's right. Huge arrays can be replaced with tuples.
tuple<char(&)[9], char(&)[8], char(&)[7], char(&)[6]> foo();
Why not an mpl::vector for that matter?
It's easy enough to extract each dimension of an array with partial specialization. Just do the representation backwards:
char (& foo( whatever ) ) [CODEN][CODEN-1]...[CODE1][CODE0]
Steve Dewhurst was here before us.
sizeof(get<0>(foo())); sizeof(get<1>(foo())); sizeof(get<2>(foo())); sizeof(get<3>(foo()));
Not sure if it compiles with boost::tuple.
Inefficient at compile time. get<N> is O(N) each time, thus the above is O(N^2); that's part of what's behind the fusion library.
I made a version of typeof_impl that uses a single function invocation and an additional encode struct invocation (in addition to encode_type) Instead of taking the size of a function, I take the size of a member of the struct returned by a function. Current version: Access element 1: sizeof(at<1>(expr)) Proposed version: Access element 1: sizeof(typeof_result(expr).value1) If this is in any way better performance-wise than the current implementation, I do not know. Peder
-- Dave Abrahams Boost Consulting www.boost-consulting.com
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

On 5/27/05, Peder Holt <peder.holt@gmail.com> wrote:
On 5/27/05, David Abrahams <dave@boost-consulting.com> wrote:
Alexander Nasonov <alnsn-boost@yandex.ru> writes:
Peder Holt <peder.holt <at> gmail.com> writes:
On 5/27/05, Alexander Nasonov <alnsn-boost <at> yandex.ru> wrote:
Sizes may become very huge, though.
If you replace your function with: char (&foo())[900][800][700][600]; you will get an overflow when calculating e.g. sizeof(foo()) / sizeof(foo()[0]), and the result will be garbage.
That's right. Huge arrays can be replaced with tuples.
tuple<char(&)[9], char(&)[8], char(&)[7], char(&)[6]> foo();
Why not an mpl::vector for that matter?
It's easy enough to extract each dimension of an array with partial specialization. Just do the representation backwards:
char (& foo( whatever ) ) [CODEN][CODEN-1]...[CODE1][CODE0]
Steve Dewhurst was here before us.
sizeof(get<0>(foo())); sizeof(get<1>(foo())); sizeof(get<2>(foo())); sizeof(get<3>(foo()));
Not sure if it compiles with boost::tuple.
Inefficient at compile time. get<N> is O(N) each time, thus the above is O(N^2); that's part of what's behind the fusion library.
I made a version of typeof_impl that uses a single function invocation and an additional encode struct invocation (in addition to encode_type)
Instead of taking the size of a function, I take the size of a member of the struct returned by a function.
Current version: Access element 1: sizeof(at<1>(expr))
Proposed version: Access element 1: sizeof(typeof_result(expr).value1)
If this is in any way better performance-wise than the current implementation, I do not know.
Peder
I did some tests on VC8 beta, and it compiles the testcase in half the time compared to the present implementation of typeof_impl. As far as I have been able to test, it also works around the compiler bug for VC8 discussed earlier. Here is a more detailed sketch of the proposed solution: namespace boost {namespace type_of{ template<typename T> struct encode_result { typedef typename encode_type<BOOST_TYPEOF_VECTOR(0)<>, T>::type encoded_type; typedef typename mpl::size<encoded_type>::type size; char (&value0)[...]; char (&value1)[...]; char (&value2)[...]; ... char (&value50)[...]; }; template<class T> encode_result<T> typeof_result(const T&); }} #define BOOST_TYPEOF_AT(n, expr) sizeof(boost::type_of::typeof_result(expr).BOOST_PP_CAT(value,n)) Peder.
-- Dave Abrahams Boost Consulting www.boost-consulting.com
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

"Peder Holt" <peder.holt@gmail.com> wrote
I did some tests on VC8 beta, and it compiles the testcase in half the time compared to the present implementation of typeof_impl. As far as I have been able to test, it also works around the compiler bug for VC8 discussed earlier.
Here is a more detailed sketch of the proposed solution:
namespace boost {namespace type_of{ template<typename T> struct encode_result { typedef typename encode_type<BOOST_TYPEOF_VECTOR(0)<>, T>::type encoded_type; typedef typename mpl::size<encoded_type>::type size; char (&value0)[...]; char (&value1)[...]; char (&value2)[...]; ... char (&value50)[...]; };
template<class T> encode_result<T> typeof_result(const T&); }} #define BOOST_TYPEOF_AT(n, expr) sizeof(boost::type_of::typeof_result(expr).BOOST_PP_CAT(value,n))
Interesting... Let me guess: char(&value2)[mpl::at<encode<T>::type, mpl::int<(2 < size) ? 2 : 0>
::type::value]; //?
Regards, Arkadiy

On 5/28/05, Arkadiy Vertleyb <vertleyb@hotmail.com> wrote:
"Peder Holt" <peder.holt@gmail.com> wrote
I did some tests on VC8 beta, and it compiles the testcase in half the time compared to the present implementation of typeof_impl. As far as I have been able to test, it also works around the compiler bug for VC8 discussed earlier.
Here is a more detailed sketch of the proposed solution:
namespace boost {namespace type_of{ template<typename T> struct encode_result { typedef typename encode_type<BOOST_TYPEOF_VECTOR(0)<>, T>::type encoded_type; typedef typename mpl::size<encoded_type>::type size; char (&value0)[...]; char (&value1)[...]; char (&value2)[...]; ... char (&value50)[...]; };
template<class T> encode_result<T> typeof_result(const T&); }} #define BOOST_TYPEOF_AT(n, expr) sizeof(boost::type_of::typeof_result(expr).BOOST_PP_CAT(value,n))
Interesting... Let me guess:
char(&value2)[mpl::at<encode<T>::type, mpl::int<(2 < size) ? 2 : 0>
::type::value]; //?
Yep :) char(&value2)[mpl::at<encoded_type,mpl::int_<(2 < size::value) ? 2 : 0>
::type::value];
Peder
Regards, Arkadiy
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

"Peder Holt" <peder.holt@gmail.com> wrote
On 5/28/05, Arkadiy Vertleyb <vertleyb@hotmail.com> wrote:
"Peder Holt" <peder.holt@gmail.com> wrote
I did some tests on VC8 beta, and it compiles the testcase in half the time compared to the present implementation of typeof_impl. As far as I have been able to test, it also works around the compiler bug for VC8 discussed earlier.
Here is a more detailed sketch of the proposed solution:
namespace boost {namespace type_of{ template<typename T> struct encode_result { typedef typename encode_type<BOOST_TYPEOF_VECTOR(0)<>, T>::type encoded_type; typedef typename mpl::size<encoded_type>::type size; char (&value0)[...]; char (&value1)[...]; char (&value2)[...]; ... char (&value50)[...]; };
template<class T> encode_result<T> typeof_result(const T&); }} #define BOOST_TYPEOF_AT(n, expr) sizeof(boost::type_of::typeof_result(expr).BOOST_PP_CAT(value,n))
Interesting... Let me guess:
char(&value2)[mpl::at<encode<T>::type, mpl::int<(2 < size) ? 2 : 0>
::type::value]; //?
Yep :)
char(&value2)[mpl::at<encoded_type,mpl::int_<(2 < size::value) ? 2 : 0>
::type::value];
Than there is no magic here :-) You just re-introduced the simple type optimization I removed to workaround the vc8 problem. Cutting performance in half was the result I got. Apparently in this simpler context vc8 is able to handle this. This workaround is much better than mine because it doesn't degrade vc8 preformance. And it might be better than the original (before workaround) solution in terms of portability -- other compilers might have the same problem vc8 has. One thing -- we might consider a function template instead of preprocessor-generated values... Althouth I believe this change _should_ be applied, along with the change that allows to remove _TPL, let's not make these changes now, and consider this more carefully after the review. Regards, Arkadiy

On 5/28/05, Arkadiy Vertleyb <vertleyb@hotmail.com> wrote:
"Peder Holt" <peder.holt@gmail.com> wrote
On 5/28/05, Arkadiy Vertleyb <vertleyb@hotmail.com> wrote:
"Peder Holt" <peder.holt@gmail.com> wrote
I did some tests on VC8 beta, and it compiles the testcase in half the time compared to the present implementation of typeof_impl. As far as I have been able to test, it also works around the compiler bug for VC8 discussed earlier.
Here is a more detailed sketch of the proposed solution:
namespace boost {namespace type_of{ template<typename T> struct encode_result { typedef typename encode_type<BOOST_TYPEOF_VECTOR(0)<>, T>::type encoded_type; typedef typename mpl::size<encoded_type>::type size; char (&value0)[...]; char (&value1)[...]; char (&value2)[...]; ... char (&value50)[...]; };
template<class T> encode_result<T> typeof_result(const T&); }} #define BOOST_TYPEOF_AT(n, expr) sizeof(boost::type_of::typeof_result(expr).BOOST_PP_CAT(value,n))
Interesting... Let me guess:
char(&value2)[mpl::at<encode<T>::type, mpl::int<(2 < size) ? 2 : 0>
::type::value]; //?
Yep :)
char(&value2)[mpl::at<encoded_type,mpl::int_<(2 < size::value) ? 2 : 0>
::type::value];
Than there is no magic here :-)
None intended :)
You just re-introduced the simple type optimization I removed to workaround the vc8 problem. Cutting performance in half was the result I got. Apparently in this simpler context vc8 is able to handle this.
Yep. I got no significant performance boost on VC7.1 or GCC with the new version.
This workaround is much better than mine because it doesn't degrade vc8 preformance. And it might be better than the original (before workaround) solution in terms of portability -- other compilers might have the same problem vc8 has. One thing -- we might consider a function template instead of preprocessor-generated values...
Not quite sure how that should work.
Althouth I believe this change _should_ be applied, along with the change that allows to remove _TPL, let's not make these changes now, and consider this more carefully after the review.
Agreed. One more thing, I also tried modifying boost::type_of::vector a bit: struct vector_base { char (&value0)[1]; char (&value1)[1]; char (&value2)[1]; ... char (&value50)[1]; }; template<typename T=void> struct vector0 : vector_base { } template<typename P0,typename T=void> struct vector1 : vector_base { char (&value0)[T0::value]; } ... template<typename P0,..typename P49,typename T=void> struct vector50 : vector_base { ... }; template<class T> typename encode_type<vector0<>,T>::type typeof_result(const T&); This seems to make a ~20% improvement on the VC compilers at least (haven't tried GCC on this change yet) Regards, Peder
Regards, Arkadiy
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

"Peder Holt" <peder.holt@gmail.com> wrote
On 5/28/05, Arkadiy Vertleyb <vertleyb@hotmail.com> wrote:
This workaround is much better than mine because it doesn't degrade vc8 preformance. And it might be better than the original (before workaround) solution in terms of portability -- other compilers might have the same problem vc8 has. One thing -- we might consider a function template instead of preprocessor-generated values...
Not quite sure how that should work.
instead of: char (&value0)[...]; char (&value1)[...]; char (&value2)[...]; ... char (&value50)[...]; just have: template<int n> char (&value(mpl::int_<n>))[...]; But now I am thinkig this may re-introduce the original performance problem...
One more thing, I also tried modifying boost::type_of::vector a bit:
struct vector_base { char (&value0)[1]; char (&value1)[1]; char (&value2)[1]; ... char (&value50)[1]; };
template<typename T=void> struct vector0 : vector_base { }
template<typename P0,typename T=void> struct vector1 : vector_base { char (&value0)[T0::value]; }
... template<typename P0,..typename P49,typename T=void> struct vector50 : vector_base { ... };
template<class T> typename encode_type<vector0<>,T>::type typeof_result(const T&);
This seems to make a ~20% improvement on the VC compilers at least (haven't tried GCC on this change yet)
Cool. I originally thought that type_of::vector<> is just a temporary workaround, until mpl::vector<> performance problem with GCC is fixed, but now I am not so sure... It was already about 20% performance improvement over mpl::vector<> on VC7 (because operations were specialized directly rather than their implementations, which resulted in fewer template instantiations). Now even better performance... I think the Typeof library is intended to be very low-level, and as such, deserves a fine-tuned custom compile-time sequence with no overhead that can't be avoided by a generic solution. The current implementation allows to easily switch from one type of such a sequence to another, which simplifies performance testing, and which may turn out useful if different sequences turn out to be the best for different compilers. I do think that we should keep the interface of the mpl::vector<>. Again, something to think about after the review. Regards, Arkadiy

Arkadiy Vertleyb <vertleyb <at> hotmail.com> writes:
I do think that we should keep the interface of the mpl::vector<>.
Again, something to think about after the review.
Can you think also about replacing vector with vector_c<size_t,...> to shorten macro expansion? -- Alexander Nasonov

Alexander Nasonov wrote:
Huge arrays can be replaced with tuples.
tuple<char(&)[9], char(&)[8], char(&)[7], char(&)[6]> foo();
sizeof(get<0>(foo())); sizeof(get<1>(foo())); sizeof(get<2>(foo())); sizeof(get<3>(foo()));
Not sure if it compiles with boost::tuple.
There is also a tuple implementation in Fusion as a part of Boost.Spirit which sould compile no problem (with the appropriate headers included): #include <boost/spirit/fusion/sequence/tuple.hpp> #include <boost/spirit/fusion/sequence/get.hpp> using namespace boost::fusion; Reece Haston Dunn Software Engineer, Sophos Web: www.sophos.com Sophos - protecting businesses against viruses and spam

"Alexander Nasonov" <alnsn-boost@yandex.ru> wrote
#include <boost/mpl/assert.hpp> #include <boost/mpl/equal.hpp> #include <boost/mpl/vector_c.hpp>
char (&foo())[9][8][7][6];
int main() { using namespace boost::mpl;
typedef vector_c< int , sizeof(foo()) / sizeof(foo()[0]) , sizeof(foo()[0]) / sizeof(foo()[0][0]) , sizeof(foo()[0][0]) / sizeof(foo()[0][0][0]) , sizeof(foo()[0][0][0]) / sizeof(foo()[0][0][0][0]) > vec;
BOOST_MPL_ASSERT(( equal< vec, vector_c<int,9,8,7,6> > )); }
An interesting alternative. Instead of passing the desired vector position into foo(), just return everything in a multi-dimensional array. Have to give it more thought... Still don't see how it would help with ODR, though... Regards, Arkadiy

"Arkadiy Vertleyb" <vertleyb@hotmail.com> writes:
"Alexander Nasonov" <alnsn-boost@yandex.ru> wrote in message
David Abrahams writes:
The function returns a reference to a multidimensional array, where each numerical element that you were putting in the mpl::vector is encoded as a separate dimension of the array.
Exactly. It's the vector returned by encode_type_impl. I didn't have a chance to think about my idea thoroughly but this is something completely different. Partial specializations aren't supported by functions,
That is a fact.
for example.
I think they are:
template<class T> char foo(vector<T>& v)[id1][id2][id3];
That's not a partial specialization; it's an overload. It's different from a specialization in that all the overloads need to be visible before the point of use unless you are going to use ADL to look up the function. -- Dave Abrahams Boost Consulting www.boost-consulting.com

"David Abrahams" <dave@boost-consulting.com> wrote
"Arkadiy Vertleyb" <vertleyb@hotmail.com> writes:
I think they are:
template<class T> char foo(vector<T>& v)[id1][id2][id3];
That's not a partial specialization; it's an overload.
Right, I used wrong terminology.
It's different from a specialization in that all the overloads need to be visible before the point of use unless you are going to use ADL to look up the function.
That maybe OK for typeof. The bigger problem is that they are not matched as strictly as specializations do. For example a derived class can be matched, etc. Regards, Arkadiy

Arkadiy Vertleyb <vertleyb <at> hotmail.com> writes:
That maybe OK for typeof. The bigger problem is that they are not matched as strictly as specializations do. For example a derived class can be matched, etc.
enable_if? -- Alexander Nasonov

"Alexander Nasonov" <alnsn-boost@yandex.ru> wrote
Arkadiy Vertleyb <vertleyb <at> hotmail.com> writes:
That maybe OK for typeof. The bigger problem is that they are not matched as strictly as specializations do. For example a derived class can be matched, etc.
enable_if?
Well, there might exist alternatives to partial template specialization, and I think Peder explored some of them in his "vintage" implementation. The question is whether it worth it. I still think partial template specialization is the most natural way of splitting a type into components. Can't see why anything else would be better... Regards, Arkadiy

Arkadiy Vertleyb <vertleyb <at> hotmail.com> writes:
"David Abrahams" <dave <at> boost-consulting.com> wrote
It's different from a specialization in that all the overloads need to be visible before the point of use unless you are going to use ADL to look up the function.
ADL could help in registering types at namespace scope. AFAIK, now it's possible only in global scope. -- Alexander Nasonov

"Alexander Nasonov" <alnsn-boost@yandex.ru> writes:
David Abrahams writes:
The function returns a reference to a multidimensional array, where each numerical element that you were putting in the mpl::vector is encoded as a separate dimension of the array.
Exactly. It's the vector returned by encode_type_impl. I didn't have a chance to think about my idea thoroughly but this is something completely different. Partial specializations aren't supported by functions, for example.
This array technique is the one used by Steve Dewhurst in his typeof implementation. -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams <dave <at> boost-consulting.com> writes:
"Alexander Nasonov" <alnsn-boost <at> yandex.ru> writes:
David Abrahams writes:
The function returns a reference to a multidimensional array, where each numerical element that you were putting in the mpl::vector is encoded as a separate dimension of the array.
Exactly. It's the vector returned by encode_type_impl. I didn't have a chance to think about my idea thoroughly but this is something completely different. Partial specializations aren't supported by functions, for example.
This array technique is the one used by Steve Dewhurst in his typeof implementation.
IIRC, he doesn't apply it to type encoding. I've tried to get rid of ODR violations of encode_type_impl but I forgot about decode_type_impl and a point of BOOST_TYPEOF invocation. I'd better went to bed yesterday night ;-) -- Alexander Nasonov

Alexander Nasonov <alnsn-boost@yandex.ru> writes:
David Abrahams <dave <at> boost-consulting.com> writes:
"Alexander Nasonov" <alnsn-boost <at> yandex.ru> writes:
David Abrahams writes:
The function returns a reference to a multidimensional array, where each numerical element that you were putting in the mpl::vector is encoded as a separate dimension of the array.
Exactly. It's the vector returned by encode_type_impl. I didn't have a chance to think about my idea thoroughly but this is something completely different. Partial specializations aren't supported by functions, for example.
This array technique is the one used by Steve Dewhurst in his typeof implementation.
IIRC, he doesn't apply it to type encoding.
IIRC he does, but you may have been paying more attention than I was. -- Dave Abrahams Boost Consulting www.boost-consulting.com

"Alexander Nasonov" <alnsn-boost@yandex.ru> writes: Re: HA: You might want to look at http://www.freeframers.org/archive/00/msg02087.html. Best reference I could find this minute with Google, sorry ;-) -- Dave Abrahams Boost Consulting www.boost-consulting.com

My linux was damaged at ACCU. Only Windows survived and I have to use it. But I don't feel comfortable there. I don't even know what 'HA' means. Sorry for inconvenience. -- Alexander Nasonov

"Alexander Nasonov" <alnsn-boost@yandex.ru> writes:
My linux was damaged at ACCU. Only Windows survived and I have to use it. But I don't feel comfortable there. I don't even know what 'HA' means. Sorry for inconvenience.
It's not really inconvenient. It's just something I thought more people should know about :) -- Dave Abrahams Boost Consulting www.boost-consulting.com
participants (6)
-
Alexander Nasonov
-
Andy Little
-
Arkadiy Vertleyb
-
David Abrahams
-
Peder Holt
-
Reece Dunn