[Review] Type Traits Introspection library by Edward Diener starts tomorrow Friday 1

According to the schedule, review for the Type Traits Introspection library by Edward Diener starts this friday and run till July 10th. =========== What is it? =========== The TTI library, which is an abbreviation for the 'Type Traits Introspection' library, allows a programmer to introspect at compile time the inner elements of a C++ type. The introspection process depends on specifying the name of the inner element by different macros for different types of elements, and then using a generated metafunction to determine whether that element exists within the enclosing type. The inner elements which can be introspected are type, class template, member data, member function, static member data, and static member function. The TTI library is based on the type_traits_ext portion of the Concept Traits Library, with improvements and additions, and also reproduces functionality ( without changing existing code ), for the purposes of completeness, from Boost.MPL regarding introspection of types and templates. The purpose of the library is to provide a consistent set of interfaces for doing compile-time introspection of a type, which other template metaprogrammers can use in their code. If you are at all interested in compile-time introspection of types, please take a look at the functionality of this library. =================== Getting the library =================== The library is available at http://svn.boost.org/svn/boost/sandbox/tti/ Note that this repository will be updated up to next thursday by Edward. =================== Writing a Review =================== The reviews and all comments should be submitted to the developers list, and the email should have "[TTI] Review" at the beginning of the subject line to make sure it's not missed. Please explicitly state in your review whether the library should be accepted. The general review checklist: - 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.

Not a review, just a couple of comments. That kind of library would be *very* valuable if it could be made to work with a wide spectrum of compilers out there. I know that kind stuff can break easily, so I'd really like to have some test results for other compilers (xlC, Intel, ...) to know whether that library is really limited to MSVC/GCC or not, in order to make a more informed evaluation. Otherwise, I also have a question: Does the library deal with static const integral data members which you cannot take the address of, and if it does, how does it do it? I mean things like struct A { static const int value = 42; };

On 7/1/2011 5:28 PM, Mathias Gaunard wrote:
Not a review, just a couple of comments.
That kind of library would be *very* valuable if it could be made to work with a wide spectrum of compilers out there.
I know that kind stuff can break easily, so I'd really like to have some test results for other compilers (xlC, Intel, ...) to know whether that library is really limited to MSVC/GCC or not, in order to make a more informed evaluation.
I will try some tests with clang. As for other compilers, I just do not have others to test against. if there are other compilers which have a free version that I can use I will do so.
Otherwise, I also have a question:
Does the library deal with static const integral data members which you cannot take the address of, and if it does, how does it do it?
I mean things like
struct A { static const int value = 42; };
That works correctly in the library for gcc and VC++. Evidently the code that tests, which uses an expression of &A::value, is accepted by those compilers. Is it illegal to take the address of a static const data member in C++ ?

I mean things like
struct A { static const int value = 42; };
That works correctly in the library for gcc and VC++. Evidently the code that tests, which uses an expression of &A::value, is accepted by those compilers. Is it illegal to take the address of a static const data member in C++ ?
No, but you *may* need an out-of-line definition for the member "value" if the compiler considers the address to be "used": my guess is you're only using it within the context of another metafunction, so probably this should be OK.... probably ;) HTH, John.

On 7/2/2011 4:44 AM, John Maddock wrote:
I mean things like
struct A { static const int value = 42; };
That works correctly in the library for gcc and VC++. Evidently the code that tests, which uses an expression of &A::value, is accepted by those compilers. Is it illegal to take the address of a static const data member in C++ ?
No, but you *may* need an out-of-line definition for the member "value" if the compiler considers the address to be "used": my guess is you're only using it within the context of another metafunction, so probably this should be OK.... probably ;)
Is there a relevant section in the C++ standard about this which you can cite offhand ? In my quick test of this I did not specify an out-of-line definition but then again I am not "using" the const value in any other way then to test against it.

No, but you *may* need an out-of-line definition for the member "value" if the compiler considers the address to be "used": my guess is you're only using it within the context of another metafunction, so probably this should be OK.... probably ;)
Is there a relevant section in the C++ standard about this which you can cite offhand ?
In my quick test of this I did not specify an out-of-line definition but then again I am not "using" the const value in any other way then to test against it.
C++11 says of these: "If a non-volatile const static data member is of integral or enumeration type, its declaration in the class definition can specify a brace-or-equal-initializer in which every initializer-clause that is an assignmentexpression is a constant expression (5.19). A static data member of literal type can be declared in the class definition with the constexpr specifier; if so, its declaration shall specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression. [ Note: In both these cases, the member may appear in constant expressions. -end note ] The member shall still be defined in a namespace scope if it is odr-used (3.2) in the program and the namespace scope definition shall not contain an initializer." I couldn't find in 3.2 where it specifies what constitutes odr-used in this case, but I did note that unevaluated-operands are excluded, so if you're using it within a constant-expression it seems you may be OK. John.

On 7/2/2011 11:41 AM, John Maddock wrote:
No, but you *may* need an out-of-line definition for the member "value" if the compiler considers the address to be "used": my guess is you're only using it within the context of another metafunction, so probably this should be OK.... probably ;)
Is there a relevant section in the C++ standard about this which you can cite offhand ?
In my quick test of this I did not specify an out-of-line definition but then again I am not "using" the const value in any other way then to test against it.
C++11 says of these:
"If a non-volatile const static data member is of integral or enumeration type, its declaration in the class definition can specify a brace-or-equal-initializer in which every initializer-clause that is an assignmentexpression is a constant expression (5.19). A static data member of literal type can be declared in the class definition with the constexpr specifier; if so, its declaration shall specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression. [ Note: In both these cases, the member may appear in constant expressions. -end note ] The member shall still be defined in a namespace scope if it is odr-used (3.2) in the program and the namespace scope definition shall not contain an initializer."
I couldn't find in 3.2 where it specifies what constitutes odr-used in this case, but I did note that unevaluated-operands are excluded, so if you're using it within a constant-expression it seems you may be OK.
I am using it within a constant expression since TTI is a compile-time library like type traits. But I am sure you already know that.

On 02/07/11 13:57, Edward Diener wrote:
On 7/2/2011 4:44 AM, John Maddock wrote:
I mean things like
struct A { static const int value = 42; };
That works correctly in the library for gcc and VC++. Evidently the code that tests, which uses an expression of &A::value, is accepted by those compilers. Is it illegal to take the address of a static const data member in C++ ?
No, but you *may* need an out-of-line definition for the member "value" if the compiler considers the address to be "used": my guess is you're only using it within the context of another metafunction, so probably this should be OK.... probably ;)
Is there a relevant section in the C++ standard about this which you can cite offhand ?
Don't have a copy of the current standard, but I can quote C++0x (N3290) [class.static.data] (9.4.2) p3: "The member shall still be defined in a namespace scope if it is odr-used (3.2) in the program and the namespace scope definition shall not contain an initializer." The implication being that no namespace-scope definition is required when it is not odr-used.
In my quick test of this I did not specify an out-of-line definition but then again I am not "using" the const value in any other way then to test against it.
The definition of odr-used ([basic.def.odr], 3.2) is quite long, but you're fine if it's an "unevaluated operand". In particular, see [expr] (5) p7: "In some contexts, unevaluated operands appear (5.2.8, 5.3.3, 5.3.7, 7.1.6.2). An unevaluated operand is not evaluated." These four references are typeid, sizeof, noexcept, and decltype. Is your use inside such an expression? I was guessing it would be in sizeof(). John Bytheway

On 7/2/2011 11:41 AM, John Bytheway wrote:
On 02/07/11 13:57, Edward Diener wrote:
On 7/2/2011 4:44 AM, John Maddock wrote:
I mean things like
struct A { static const int value = 42; };
That works correctly in the library for gcc and VC++. Evidently the code that tests, which uses an expression of&A::value, is accepted by those compilers. Is it illegal to take the address of a static const data member in C++ ?
No, but you *may* need an out-of-line definition for the member "value" if the compiler considers the address to be "used": my guess is you're only using it within the context of another metafunction, so probably this should be OK.... probably ;)
Is there a relevant section in the C++ standard about this which you can cite offhand ?
Don't have a copy of the current standard, but I can quote C++0x (N3290) [class.static.data] (9.4.2) p3:
"The member shall still be defined in a namespace scope if it is odr-used (3.2) in the program and the namespace scope definition shall not contain an initializer."
The implication being that no namespace-scope definition is required when it is not odr-used.
In my quick test of this I did not specify an out-of-line definition but then again I am not "using" the const value in any other way then to test against it.
The definition of odr-used ([basic.def.odr], 3.2) is quite long, but you're fine if it's an "unevaluated operand". In particular, see [expr] (5) p7:
"In some contexts, unevaluated operands appear (5.2.8, 5.3.3, 5.3.7, 7.1.6.2). An unevaluated operand is not evaluated."
These four references are typeid, sizeof, noexcept, and decltype. Is your use inside such an expression? I was guessing it would be in sizeof().
Yes it is sizeof().

According to the schedule, review for the Type Traits Introspection library by Edward Diener starts this friday and run till July 10th.
Not a review yet, just a quick run of the tests: msvc-8,9 and 10 check out OK. GCC-4.0.4, 4.4.3 4.5.2 and 4.6.0 check out OK (on Linux). Intel 11.1 and 12.0 both have failures, as does Sun-12.1 and the rather ancient gcc-3.2.3. Of these the Intel failures are the only ones that worry me, as the EDG frontend is generally considered pretty std-conforming. I'm attaching the error logs in case Edward wants to take a look. HTH, John.

On 7/2/2011 2:08 PM, John Maddock wrote:
According to the schedule, review for the Type Traits Introspection library by Edward Diener starts this friday and run till July 10th.
Not a review yet, just a quick run of the tests:
msvc-8,9 and 10 check out OK. GCC-4.0.4, 4.4.3 4.5.2 and 4.6.0 check out OK (on Linux).
Intel 11.1 and 12.0 both have failures, as does Sun-12.1 and the rather ancient gcc-3.2.3.
Of these the Intel failures are the only ones that worry me, as the EDG frontend is generally considered pretty std-conforming.
I'm attaching the error logs in case Edward wants to take a look.
Thanks ! Frederick Bron also sent me Intel 11.1 failures, so I will look at both your generated results and his.

On 7/2/2011 2:08 PM, John Maddock wrote:
According to the schedule, review for the Type Traits Introspection library by Edward Diener starts this friday and run till July 10th.
Not a review yet, just a quick run of the tests:
msvc-8,9 and 10 check out OK. GCC-4.0.4, 4.4.3 4.5.2 and 4.6.0 check out OK (on Linux).
Intel 11.1 and 12.0 both have failures, as does Sun-12.1 and the rather ancient gcc-3.2.3.
I am not worried about gcc-3.2.3 very much as my own tests showed that gcc-3.3.3 and below did not work. I can look at this later to try to see why, but since gcc-3.4.2 on up work I just think that trying to get gcc-3.3.3 and below to work may not be worth it. For Intel 11.1 or 12.0 can you tell me if the MPL tests pass, particularly just the test of has_xxx.cpp ? If that fails for MPL it fully explains why my tests for Intel are failing ( I am just reusing BOOST_MPL_HAS_XXX_TEMPLATE_NAMED_DEF internally ) and a workaround would need to be found in MPL. I am still looking at the Sun-12.1 results and will get back later about it.

For Intel 11.1 or 12.0 can you tell me if the MPL tests pass, particularly just the test of has_xxx.cpp ? If that fails for MPL it fully explains why my tests for Intel are failing ( I am just reusing BOOST_MPL_HAS_XXX_TEMPLATE_NAMED_DEF internally ) and a workaround would need to be found in MPL.
Ah: there are failures for mpl with Intel as well - results attached. John.

On 7/4/2011 7:07 AM, John Maddock wrote:
For Intel 11.1 or 12.0 can you tell me if the MPL tests pass, particularly just the test of has_xxx.cpp ? If that fails for MPL it fully explains why my tests for Intel are failing ( I am just reusing BOOST_MPL_HAS_XXX_TEMPLATE_NAMED_DEF internally ) and a workaround would need to be found in MPL.
Ah: there are failures for mpl with Intel as well - results attached.
Thanks ! If you can, is it possible to get the preprocessor output decently formatted for Intel Linux 12.0 when it expands the macro BOOST_MPL_HAS_XXX_TEMPLATE_NAMED_DEF on line 20 of boost/libs/mpl/test/has_xxx.cpp ? There is no rush and if you find it is too much work, I will understand. The issue is that BOOST_MPL_HAS_XXX_TEMPLATE_NAMED_DEF is quite complicated, has workarounds for various scenarios mainly involving some releases of VC++, and it appears that Intel 11.1 and Intel 12.0 also can't handle the normal macro generated metafunction properly. David Abrahams and Alex Gurtovoy may have done the initial work on this macro for MPL, but it seems as if Daniel Walker also did improvements. I am using this macro in TTI and also developed another macro based on it for finding an exact match for a nested template ( the MPL implementations looks for a match with every macro parameter being a typename/class up to 5 ) . So to get Intel 11.1 and 12.0 to work, both BOOST_MPL_HAS_XXX_TEMPLATE_NAMED_DEF and my own macro needs to find a workaround, but once BOOST_MPL_HAS_XXX_TEMPLATE_NAMED_DEF has an Intel workaround doing my own will be relatively easy. Of course the failure is with the Intel compiler in this case but I need to find out exactly how it is expanding the macro just in case its preprocessor is in error somehow. I have expanded the macro using Wave, and I am pretty sure that is what the Intel output is also, but I would like to check if possible. The Wave output is: template<typename T,typename fallback_ = boost::mpl::bool_< false > > class has_xxx_template { template< typename U > struct has_xxx_template_introspect { template<template< typename V0 > class V> struct has_xxx_template_substitute0 {}; template<template< typename V0 , typename V1 > class V > struct has_xxx_template_substitute1 {}; template<template< typename V0 , typename V1 , typename V2 > class V > struct has_xxx_template_substitute2 {}; template<template< typename V0 , typename V1 , typename V2 , typename V3 > class V > struct has_xxx_template_substitute3 {}; template<template< typename V0 , typename V1 , typename V2 , typename V3 , typename V4 > class V > struct has_xxx_template_substitute4 {}; template< typename V > static boost::mpl::aux::no_tag has_xxx_template_test(...); template< typename V > static boost::mpl::aux::yes_tag has_xxx_template_test ( boost::mpl::aux::type_wrapper< V > const volatile*, has_xxx_template_substitute0 <V::template xxx>* = 0 ); template< typename V > static boost::mpl::aux::yes_tag has_xxx_template_test ( boost::mpl::aux::type_wrapper< V > const volatile*, has_xxx_template_substitute1 <V::template xxx>* = 0 ); template< typename V > static boost::mpl::aux::yes_tag has_xxx_template_test ( boost::mpl::aux::type_wrapper< V > const volatile*, has_xxx_template_substitute2 <V::template xxx>* = 0 ); template< typename V > static boost::mpl::aux::yes_tag has_xxx_template_test ( boost::mpl::aux::type_wrapper< V > const volatile*, has_xxx_template_substitute3 <V::template xxx>* = 0 ); template< typename V > static boost::mpl::aux::yes_tag has_xxx_template_test ( boost::mpl::aux::type_wrapper< V > const volatile*, has_xxx_template_substitute4 <V::template xxx>* = 0 ); static const bool value = sizeof(has_xxx_template_test< U >(0)) == sizeof(boost::mpl::aux::yes_tag); typedef boost::mpl::bool_< value > type; }; public: static const bool value = has_xxx_template_introspect< T >::value; typedef typename has_xxx_template_introspect<T>::type type; }; The error meesage from the Intel compiler is: has_xxx.cpp(20): error: more than one instance of overloaded function "has_xxx_template<T, fallback_>::has_xxx_template_introspect<U>::has_xxx_template_test [with T=a5, fallback_=boost::mpl::bool_<false>, U=a5]" matches the argument list: function template "boost::mpl::aux::yes_tag has_xxx_template<T, fallback_>::has_xxx_template_introspect<U>::has_xxx_template_test(const volatile boost::mpl::aux::type_wrapper<V> *, has_xxx_template<a5, boost::mpl::bool_<false>>::has_xxx_template_introspect<a5>::has_xxx_template_substitute0<V::xxx> *) [with T=a5, fallback_=boost::mpl::bool_<false>, U=a5]" function template "boost::mpl::aux::yes_tag has_xxx_template<T, fallback_>::has_xxx_template_introspect<U>::has_xxx_template_test(const volatile boost::mpl::aux::type_wrapper<V> *, has_xxx_template<a5, boost::mpl::bool_<false>>::has_xxx_template_introspect<a5>::has_xxx_template_substitute1<V::xxx> *) [with T=a5, fallback_=boost::mpl::bool_<false>, U=a5]" function template "boost::mpl::aux::yes_tag has_xxx_template<T, fallback_>::has_xxx_template_introspect<U>::has_xxx_template_test(const volatile boost::mpl::aux::type_wrapper<V> *, has_xxx_template<a5, boost::mpl::bool_<false>>::has_xxx_template_introspect<a5>::has_xxx_template_substitute2<V::xxx> *) [with T=a5, fallback_=boost::mpl::bool_<false>, U=a5]" function template "boost::mpl::aux::yes_tag has_xxx_template<T, fallback_>::has_xxx_template_introspect<U>::has_xxx_template_test(const volatile boost::mpl::aux::type_wrapper<V> *, has_xxx_template<a5, boost::mpl::bool_<false>>::has_xxx_template_introspect<a5>::has_xxx_template_substitute3<V::xxx> *) [with T=a5, fallback_=boost::mpl::bool_<false>, U=a5]" function template "boost::mpl::aux::yes_tag has_xxx_template<T, fallback_>::has_xxx_template_introspect<U>::has_xxx_template_test(const volatile boost::mpl::aux::type_wrapper<V> *, has_xxx_template<a5, boost::mpl::bool_<false>>::has_xxx_template_introspect<a5>::has_xxx_template_substitute4<V::xxx> *) [with T=a5, fallback_=boost::mpl::bool_<false>, U=a5]" argument types are: (int) BOOST_MPL_HAS_XXX_TEMPLATE_NAMED_DEF(has_xxx_template, xxx, false) ^ detected during: instantiation of class "has_xxx_template<T, fallback_>::has_xxx_template_introspect<U> [with T=a5, fallback_=boost::mpl::bool_<false>, U=a5]" at line 20 instantiation of class "has_xxx_template<T, fallback_> [with T=a5, fallback_=boost::mpl::bool_<false>]" at line 148 of "../../../boost/mpl/assert.hpp" instantiation of class "boost::mpl::assert_arg_pred_not<P> [with P=has_xxx_template<a5, boost::mpl::bool_<false>>]" at line 82 For Intel, this is really an issue that needs to be addressed in MPL and then I will attempt to update my own macro for finding an exact match based on it. It also appears as if Intel needs to fix their compiler for future releases since the same code is handled by other compilers properly.

On 7/4/2011 7:07 AM, John Maddock wrote:
For Intel 11.1 or 12.0 can you tell me if the MPL tests pass, particularly just the test of has_xxx.cpp ? If that fails for MPL it fully explains why my tests for Intel are failing ( I am just reusing BOOST_MPL_HAS_XXX_TEMPLATE_NAMED_DEF internally ) and a workaround would need to be found in MPL.
Ah: there are failures for mpl with Intel as well - results attached.
Thanks !
If you can, is it possible to get the preprocessor output decently formatted for Intel Linux 12.0 when it expands the macro BOOST_MPL_HAS_XXX_TEMPLATE_NAMED_DEF on line 20 of boost/libs/mpl/test/has_xxx.cpp ? There is no rush and if you find it is too much work, I will understand.
Reduced test case below compiles with VC++ and G++ but not Intel: I'll report it to Intel later. John. template <bool b> struct bool_ { static const bool value = b; }; template< typename T > struct type_wrapper { typedef T type; }; template< typename T , typename fallback_ = bool_< false > > class has_xxx_template { template< typename U > struct has_xxx_template_introspect { template< template< typename V0 > class V > struct has_xxx_template_substitute0 { }; template< template< typename V0 , typename V1 > class V > struct has_xxx_template_substitute1 { }; template< template< typename V0 , typename V1 , typename V2 > class V
struct has_xxx_template_substitute2 { }; template< template< typename V0 , typename V1 , typename V2 , typename V3 > class V > struct has_xxx_template_substitute3 { }; template< template< typename V0 , typename V1 , typename V2 , typename V3 , typename V4 > class V > struct has_xxx_template_substitute4 { }; template< typename V > static char has_xxx_template_test(...); template< typename V > static double has_xxx_template_test( type_wrapper< V > const volatile* , has_xxx_template_substitute0 < V::template xxx > * = 0 ); template< typename V > static double has_xxx_template_test( type_wrapper< V > const volatile* , has_xxx_template_substitute1 < V::template xxx > * = 0 ); template< typename V > static double has_xxx_template_test( type_wrapper< V > const volatile* , has_xxx_template_substitute2 < V::template xxx > * = 0 ); template< typename V > static double has_xxx_template_test( type_wrapper< V > const volatile* , has_xxx_template_substitute3 < V::template xxx > * = 0 ); template< typename V > static double has_xxx_template_test( type_wrapper< V > const volatile* , has_xxx_template_substitute4 < V::template xxx > * = 0 ); static const bool value = sizeof(has_xxx_template_test< U >(0)) == sizeof(double); typedef bool_< value > type; }; public: static const bool value = has_xxx_template_introspect< T > ::value; typedef typename has_xxx_template_introspect< T > ::type type; }; struct a5 { template< typename T > struct xxx {}; }; int main() { typedef int a[has_xxx_template<a5>::value ? 1 : -1]; }

For Intel 11.1 or 12.0 can you tell me if the MPL tests pass, particularly just the test of has_xxx.cpp ? If that fails for MPL it fully explains why my tests for Intel are failing ( I am just reusing BOOST_MPL_HAS_XXX_TEMPLATE_NAMED_DEF internally ) and a workaround would need to be found in MPL.
Ah: there are failures for mpl with Intel as well - results attached.
Thanks !
If you can, is it possible to get the preprocessor output decently formatted for Intel Linux 12.0 when it expands the macro BOOST_MPL_HAS_XXX_TEMPLATE_NAMED_DEF on line 20 of boost/libs/mpl/test/has_xxx.cpp ? There is no rush and if you find it is too much work, I will understand.
Intel support ID is #635997, will let you know the outcome, John.

On 7/5/2011 8:29 AM, John Maddock wrote:
For Intel 11.1 or 12.0 can you tell me if the MPL tests pass, particularly just the test of has_xxx.cpp ? If that fails for MPL it fully explains why my tests for Intel are failing ( I am just reusing BOOST_MPL_HAS_XXX_TEMPLATE_NAMED_DEF internally ) and a workaround would need to be found in MPL.
Ah: there are failures for mpl with Intel as well - results attached.
Thanks !
If you can, is it possible to get the preprocessor output decently formatted for Intel Linux 12.0 when it expands the macro BOOST_MPL_HAS_XXX_TEMPLATE_NAMED_DEF on line 20 of boost/libs/mpl/test/has_xxx.cpp ? There is no rush and if you find it is too much work, I will understand.
Intel support ID is #635997, will let you know the outcome,
Thanks ! Can you somehow alert the MPL programmers about this if they are not reading this thread ?

On 7/5/2011 11:52 AM, Joel falcou wrote:
On 05/07/11 10:44, Edward Diener wrote:
Thanks ! Can you somehow alert the MPL programmers about this if they are not reading this thread ?
I am ;_)
file a ticket and assign it to me, I'll try to get a solution out
I have just filed a ticket with you as the owner. It is https://svn.boost.org/trac/boost/ticket/5672. If you need help with BOOST_MPL_HAS_XXX_TEMPLATE_NAMED_DEF I will help as much as possible but I believe that Daniel Walker is the main resource.

Joel Falcou wrote:
According to the schedule, review for the Type Traits Introspection library by Edward Diener starts this friday and run till July 10th.
The library is available at http://svn.boost.org/svn/boost/sandbox/tti/
Could we please have HTML docs online somewhere? (Or have I missed them?) Thanks, Phil.

On 7/2/2011 3:38 PM, Phil Endecott wrote:
Joel Falcou wrote:
According to the schedule, review for the Type Traits Introspection library by Edward Diener starts this friday and run till July 10th.
The library is available at http://svn.boost.org/svn/boost/sandbox/tti/
Could we please have HTML docs online somewhere? (Or have I missed them?)
They are at libs/tti/doc/html/index.html.

According to the schedule, review for the Type Traits Introspection library by Edward Diener starts this friday and run till July 10th.
The library is available at http://svn.boost.org/svn/boost/sandbox/tti/
Could we please have HTML docs online somewhere? (Or have I missed them?)
You can view them online at: http://svn.boost.org/svn/boost/sandbox/tti/libs/tti/doc/html/index.html HTH, John.

On 01/07/11 03:08, Joel Falcou wrote:
According to the schedule, review for the Type Traits Introspection library by Edward Diener starts this friday and run till July 10th.
This is not a review, but some initial thoughts: You mention early in the docs the risk of ODR violations from declaring the same metafunction more than once. It seems to me that this is very likely to occur when multiple libraries want to introspect the same names. For example, if two libraries both include BOOST_TTI_HAS_TYPE(type) then I will not be able to use both these libraries in my program; is that right? This seems a serious deficiency. I feel it would be better to generate these macro metafunctions in a namespace specific to the code that wants to use them, rather than putting them all in boost::tti. That would essentially eliminate the risk of cross-library ODR violations. What is your motivation for putting all the macro metafunctions in the same namespace? John Bytheway

On 7/3/2011 7:05 AM, John Bytheway wrote:
On 01/07/11 03:08, Joel Falcou wrote:
According to the schedule, review for the Type Traits Introspection library by Edward Diener starts this friday and run till July 10th.
This is not a review, but some initial thoughts:
You mention early in the docs the risk of ODR violations from declaring the same metafunction more than once. It seems to me that this is very likely to occur when multiple libraries want to introspect the same names. For example, if two libraries both include
BOOST_TTI_HAS_TYPE(type)
then I will not be able to use both these libraries in my program; is that right?
Correct.
This seems a serious deficiency. I feel it would be better to generate these macro metafunctions in a namespace specific to the code that wants to use them, rather than putting them all in boost::tti. That would essentially eliminate the risk of cross-library ODR violations. What is your motivation for putting all the macro metafunctions in the same namespace?
You have made a very good point. My intention, evidently misguided, was to put the generated metafunctions in the boost::tti namespace to avoid polluting the global namespace. But I see now that I should not have added a namespace at all and the end-user could then use the macros in whatever namespace he wants in order to avoid ODR violations, and/or just use the complicated macro form to create a unique name for the metafunction. Actually, of course, that still could be done, but a full metafuncion name of 'anamespace::boost::tti::has_type_mytype' is more gruesome than 'anamespace::has_type_mytype'. Thanks for pointing this out.

On 03/07/11 07:21, Edward Diener wrote:
You have made a very good point.
My intention, evidently misguided, was to put the generated metafunctions in the boost::tti namespace to avoid polluting the global namespace. But I see now that I should not have added a namespace at all and the end-user could then use the macros in whatever namespace he wants in order to avoid ODR violations, and/or just use the complicated macro form to create a unique name for the metafunction. Actually, of course, that still could be done, but a full metafuncion name of 'anamespace::boost::tti::has_type_mytype' is more gruesome than 'anamespace::has_type_mytype'.
Thanks for pointing this out.
When i developed the very similar code that you have now, I purposely made the macro not generate namespace around. I think that is what BOOST_MPL_HAS_XXX does anyway. Let the user call the macro in the namespace of its choice.

On 07/03/2011 02:21 PM, Edward Diener wrote:
This seems a serious deficiency. I feel it would be better to generate these macro metafunctions in a namespace specific to the code that wants to use them, rather than putting them all in boost::tti. That would essentially eliminate the risk of cross-library ODR violations. What is your motivation for putting all the macro metafunctions in the same namespace?
You have made a very good point.
My intention, evidently misguided, was to put the generated metafunctions in the boost::tti namespace to avoid polluting the global namespace. But I see now that I should not have added a namespace at all and the end-user could then use the macros in whatever namespace he wants in order to avoid ODR violations, and/or just use the complicated macro form to create a unique name for the metafunction. Actually, of course, that still could be done, but a full metafuncion name of 'anamespace::boost::tti::has_type_mytype' is more gruesome than 'anamespace::has_type_mytype'.
Thanks for pointing this out.
How about checking with the preprocessor if the meta-function has already been defined, and not defining it in that case?

AMDG On 07/03/2011 08:17 AM, Mathias Gaunard wrote:
On 07/03/2011 02:21 PM, Edward Diener wrote:
My intention, evidently misguided, was to put the generated metafunctions in the boost::tti namespace to avoid polluting the global namespace. But I see now that I should not have added a namespace at all and the end-user could then use the macros in whatever namespace he wants in order to avoid ODR violations, and/or just use the complicated macro form to create a unique name for the metafunction. Actually, of course, that still could be done, but a full metafuncion name of 'anamespace::boost::tti::has_type_mytype' is more gruesome than 'anamespace::has_type_mytype'.
Thanks for pointing this out.
How about checking with the preprocessor if the meta-function has already been defined, and not defining it in that case?
That isn't possible. The only way to indicate to the preprocessor that the metafuction has been defined is to define a macro, and a macro can't define another macro. In Christ, Steven Watanabe

OK here's my review of this library. First off the headline - yes I believe it's a useful library that should be accepted into Boost, subject to some of the comments below.
- What is your evaluation of the design?
Probably too many macros - see detailed comments below, otherwise fine.
- What is your evaluation of the implementation?
The library is more or less a meta-library around MPL (or else uses MPL-like implementation techniques, and IMO that's the right way to go.
- What is your evaluation of the documentation?
Nice and complete, but confused me in places (see below).
- What is your evaluation of the potential usefulness of the library?
Very useful, I could have used this a few times in the past.
- Did you try to use the library? With what compiler? Did you have any problems?
There are issues with the Intel compiler which Edward is investigating - see also detailed comments below
- How much effort did you put into your evaluation? A glance? A quick reading? In-depth study?
Full read of the docs, and about an hour playing with the code. Will spend some more time getting to the bottom of the Intel issue shortly.
- Are you knowledgeable about the problem domain?
As I maintain the type traits lib I hope so, though I confess to *not* being a hard core meta-programmer :-0
- Do you think the library should be accepted as a Boost library?
Yes, subject to the comments below. Detailed comments: ~~~~~~~~~~~~~ 1) I agree with the other comments that it's basically just plain wrong to insert the generated traits classes in a namespace: they should appear within the current namespace scope. Under "General Functionality" the "Important" block should (IMO) encourage users to place macro invocations within a private "detail" namespace to avoid name clashes from multiple use in multiple headers. 2) Further to the above, I wonder if it's worthwhile providing a set of "standard" introspection classes for the common cases, a straw man list would be something like: Types: type, value_type, size_type, difference_type, iterator, const_iterator, pointer, const_pointer, reference, const_reference. Static Values: value Functions: begin(), end(), swap(self_type) 3) I was confused by the section "Macro Metafunction Name Generation", I think some examples would help a lot. Does the variety of macros supplied get simplified by just dumping the generated trait in the current namespace? 4) BOOST_TTI_MEMBER_TYPE looks like it would be more useful (to me anyway!) if the generated template would accept a second optional parameter that is the value of the ::type member when the type being checked does not have the specified inner type (hope that makes sense). 5) The description of "Table 1.4. TTI Nested Type Macro Metafunction Existence" makes no sense to me (though it might later in the docs of course). 6) I found code formatting such as: boost::tti::has_static_member_data_DSMember < T, short
A little hard to read, as long as the lines don't get too long I would much prefer: has_static_member_data_DSMember<T, short> 7) I'm not sure about the term "composite types": to me it's a member function pointer type, or if you prefer a function signature. So instead of BOOST_TTI_HAS_COMP_MEMBER_FUNCTION I'd prefer BOOST_TTI_HAS_MEMBER_FUNCTION_WITH_SIG. In fact, I think the version with function-signature should be the main variant, so maybe BOOST_TTI_HAS_MEMBER_FUNCTION(IntFunction) would become: has_member_function_IntFunction<int (T::*)(short)> and some other name should be provided for the mpl::sequence version - if it's there at all? I'm also thinking that what folks really want to know is: "Is there a function named X, that can be called with arguments of types A, B and C". It would be interesting to see how far along this road we could actually get? 8) I confess I haven't done any metaprogramming lately, but the purpose of the sections "Macro Metafunctions as Metadata" and "Nullary Type Metafunctions" completely eluded me. So I'd like to know if this is just me ;-) My gut feeling at present is that the macros in these sections don't add much to the library and will likely confuse the heck out of new users, so I guess I'd like to see better descriptions and some killer use cases before accepting these parts.... but more opinions please! 9) Great shame about the nested function template issue - hopefully someone can find a workaround. 10) Small point, but in the reference docs, for example for BOOST_TTI_TRAIT_HAS_COMP_MEMBER_FUNCTION(trait, name), it says: "returns = a metafunction called "boost::tti::trait" where 'trait' is the macro parameter." But it doesn't really return anything, rather it's a code generator. So I'd rather it said that it generates a metafunction: template<class T> struct trait { static const value = unspecified; typedef mpl::bool_<true-or-false> type; }; Then go on to define T, value, and type (I assume there is a member named type??). 11) In the docs the main header file should be given as boost/tti/tti.hpp rather than just tti.hpp. 12) Testing BOOST_TTI_HAS_COMP_MEMBER_FUNCTION(begin) I see that this static assertion fails: BOOST_STATIC_ASSERT((boost::tti::has_comp_member_function_begin<std::vector<int>::const_iterator (std::vector<int>::*const)(void)>::value)); Have I done something silly? Testing const-member functions seems OK with BOOST_TTI_HAS_MEMBER_FUNCTION BTW. Regards, John.

On 7/5/2011 4:38 AM, John Maddock wrote:
OK here's my review of this library.
Thanks for the review.
First off the headline - yes I believe it's a useful library that should be accepted into Boost, subject to some of the comments below.
Appreciated.
- What is your evaluation of the design?
Probably too many macros - see detailed comments below, otherwise fine.
You know what Mozart said to the Emperor Joseph when the latter said there were "just too many notes in 'The Marriage of Figaro'", don't you ? <g>.
- What is your evaluation of the implementation?
The library is more or less a meta-library around MPL (or else uses MPL-like implementation techniques, and IMO that's the right way to go.
- What is your evaluation of the documentation?
Nice and complete, but confused me in places (see below).
- What is your evaluation of the potential usefulness of the library?
Very useful, I could have used this a few times in the past.
- Did you try to use the library? With what compiler? Did you have any problems?
There are issues with the Intel compiler which Edward is investigating - see also detailed comments below
- How much effort did you put into your evaluation? A glance? A quick reading? In-depth study?
Full read of the docs, and about an hour playing with the code. Will spend some more time getting to the bottom of the Intel issue shortly.
- Are you knowledgeable about the problem domain?
As I maintain the type traits lib I hope so, though I confess to *not* being a hard core meta-programmer :-0
- Do you think the library should be accepted as a Boost library?
Yes, subject to the comments below.
Detailed comments: ~~~~~~~~~~~~~
1) I agree with the other comments that it's basically just plain wrong to insert the generated traits classes in a namespace: they should appear within the current namespace scope. Under "General Functionality" the "Important" block should (IMO) encourage users to place macro invocations within a private "detail" namespace to avoid name clashes from multiple use in multiple headers.
I agree with the criticism by others that it was wrong to put the generated metafunctions in a namespace and I will remove that. I will add documentation which explains further about the possibility of name clashes for the generated macros and why users of the macros should invoke the macros in a namespace which will not clash with other users or their own names.
2) Further to the above, I wonder if it's worthwhile providing a set of "standard" introspection classes for the common cases, a straw man list would be something like:
Types: type, value_type, size_type, difference_type, iterator, const_iterator, pointer, const_pointer, reference, const_reference. Static Values: value Functions: begin(), end(), swap(self_type)
That can be easily done once it is determined what to cover.
3) I was confused by the section "Macro Metafunction Name Generation", I think some examples would help a lot. Does the variety of macros supplied get simplified by just dumping the generated trait in the current namespace?
I will move the explanations in that section near the beginning of the subsequent topic on "Macro Metafunctions" and explain it better. I had adopted the idea of the macro metafunction name generation macros fairly late in the development when I realized that it would be easier creating such macros directly based off of the name of the macro metafunctions themselves rather than asking the end-user to remember a naming scheme. When I remove the putting of the macros metafunctions in the boost::tti namespace the set of macro metafunction name generation macros will be cut in half. The basic idea of the name generation macros is that for a macro metafunction named, as an example, BOOST_TTI_HAS_TYPE the metafunction name generated is given by BOOST_TTI_HAS_TYPE_GEN. In other words the metafunction name for a macro metafunction X(name) is X_GEN(name). This will be part of the better explanation.
4) BOOST_TTI_MEMBER_TYPE looks like it would be more useful (to me anyway!) if the generated template would accept a second optional parameter that is the value of the ::type member when the type being checked does not have the specified inner type (hope that makes sense).
Yes, it makes sense. I can certainly add this with no problem, but I am wondering what the use case for this situation would be. The use of BOOST_TTI_MEMBER_TYPE is simply to pass a type which may not actually exist as a nested type, and let the TTI metafunctions operate with such a type without generating a compiler error. Also the end-user can always check if such a type is a valid type using the boost::tti::valid_member_type metafunction. With all the above said, allowing the end-user to specify whatever type he wants as his "invalid type" certainly seems easy enough to do.
5) The description of "Table 1.4. TTI Nested Type Macro Metafunction Existence" makes no sense to me (though it might later in the docs of course).
I will re-explain this better in the doc as the check for an "invalid type" when using BOOST_TTI_MEMBER_TYPE.
6) I found code formatting such as:
boost::tti::has_static_member_data_DSMember < T, short
A little hard to read, as long as the lines don't get too long I would much prefer:
has_static_member_data_DSMember<T, short>
I can change this. The former, strangely enough, is my own preferred way of looking at template code. But I do understand I am adding many extra lines to the code formatting when I do this.
7) I'm not sure about the term "composite types": to me it's a member function pointer type, or if you prefer a function signature. So instead of BOOST_TTI_HAS_COMP_MEMBER_FUNCTION I'd prefer BOOST_TTI_HAS_MEMBER_FUNCTION_WITH_SIG.
I have no problem with that.
In fact, I think the version with function-signature should be the main variant, so maybe BOOST_TTI_HAS_MEMBER_FUNCTION(IntFunction) would become:
has_member_function_IntFunction<int (T::*)(short)>
and some other name should be provided for the mpl::sequence version - if it's there at all?
I feel the mpl sequence version should be the main version. the reasons for that are as follows: 1) The mpl sequence versions follows the idea that the types in all the metafunctions should be broken down into individual types as much as possible. This is useful because one can then use the functionality in BOOST_TTI_MEMBER_TYPE to pass a nested type in any of the generated metafunctions, which may not actually exist, without producing a compiler error. 2) The reason for having the composite form of the member function ( or static member function ) at all was so one could enter a calling convention ( or possible some other compiler specific addition to member function or composite function syntax ) which the Boost function_types library does not cover through one of its tag types. Without this consideration I would have eliminated the composite type syntax completely, even if specifying it is syntactically easier than using the mpl sequence. I would have done this purely for the sake of keeping the idea of individual types as regular as possible. But since some compilers use strange calling conventions and occasionally other compiler-specific conventions when specifying function syntax I decided it was important to allow this composite syntax directly.
I'm also thinking that what folks really want to know is: "Is there a function named X, that can be called with arguments of types A, B and C". It would be interesting to see how far along this road we could actually get?
I think Eric Niebler is the expert in this area regarding non-nested functions. But if he and others with more knowledge of determining this for free functions would be willing to help me I can certainly look at it in the future. I just do not think it belongs in this particular library as I conceive of it presently.
8) I confess I haven't done any metaprogramming lately, but the purpose of the sections "Macro Metafunctions as Metadata" and "Nullary Type Metafunctions" completely eluded me. So I'd like to know if this is just me ;-)
My gut feeling at present is that the macros in these sections don't add much to the library and will likely confuse the heck out of new users, so I guess I'd like to see better descriptions and some killer use cases before accepting these parts.... but more opinions please!
The whole idea of this secondary set was to avoid manually having to drag out the ::type syntactically from the basic macro metafunctions when doing nested queries such as: Does class X have a class Y which has a class Z which has a member function of signature A ? Once one gets into any sort of deeply nested query with TTI using the macro metafunctions involves quite a bit of ::type syntactical notation and the nullary type metafunctions eliminate that for the end user. Honestly I do think they serve a nice syntactical shortcut purpose and if they are confusing to you and others I would say to just ignore them. Of course I can remove them from the library without any loss of functionality, but I feel syntactical ease of use is worth it. If there is a specific way, other than more examples, I can explain the nullary metafunction syntax better, I would love to hear it. I will add a section showing the synatctic difference using the macro metafunctions and the nullary type metafunctions, with more examples.
9) Great shame about the nested function template issue - hopefully someone can find a workaround.
Calling Daniel Walker ( or perhaps Dave Abrahams and Alexsey Gurtovoy ). I more or less understand what the generated macros are doing but the issues of what it takes for a compiler to compile the code correctly are harder. There is a workaround which some earlier version of VC++ accepts so maybe it can be used with Intel 11.1 and 12.0. I will experiment. My own specific template match is heavily based on the MPL code so once a workaround can be found for Intel compiler for the MPL code, finding the same workaround for my specific template match code should be relatively easy.
10) Small point, but in the reference docs, for example for BOOST_TTI_TRAIT_HAS_COMP_MEMBER_FUNCTION(trait, name), it says:
"returns = a metafunction called "boost::tti::trait" where 'trait' is the macro parameter."
But it doesn't really return anything, rather it's a code generator. So I'd rather it said that it generates a metafunction:
template<class T> struct trait { static const value = unspecified; typedef mpl::bool_<true-or-false> type; };
Then go on to define T, value, and type (I assume there is a member named type??).
Agreed. 'Returns a metafunction' should always be 'generates a metafunction' with the appropriate metafunction explanation.
11) In the docs the main header file should be given as boost/tti/tti.hpp rather than just tti.hpp.
I will change that.
12) Testing BOOST_TTI_HAS_COMP_MEMBER_FUNCTION(begin)
I see that this static assertion fails:
BOOST_STATIC_ASSERT((boost::tti::has_comp_member_function_begin<std::vector<int>::const_iterator (std::vector<int>::*const)(void)>::value));
Have I done something silly?
No, it is a bug. I am looking into it. I thought I wrote some thorough tests but I now see I needed to test more. I did not write any tests for const member function or const static data, and that was poor of me.
Testing const-member functions seems OK with BOOST_TTI_HAS_MEMBER_FUNCTION BTW.
Yes, this works. I have to figure out why one and not the other works and I will. Somehow the function types library is doing something very clever when composing a member function type which the direct syntax does not have. Thanks for all the comments and taking the time to look at the library and try things out. Eddie Diener

On 05/07/11 10:35, Edward Diener wrote:
2) Further to the above, I wonder if it's worthwhile providing a set of "standard" introspection classes for the common cases, a straw man list would be something like:
Types: type, value_type, size_type, difference_type, iterator, const_iterator, pointer, const_pointer, reference, const_reference. Static Values: value Functions: begin(), end(), swap(self_type)
That can be easily done once it is determined what to cover.
metafunctions for preexisting concepts could be nice. Bonsu point if they live in a tti/std/???.hpp set of files. Basically w/e testing for Container, Range and other common concepts should be enough.
I'm also thinking that what folks really want to know is: "Is there a function named X, that can be called with arguments of types A, B and C". It would be interesting to see how far along this road we could actually get?
I think Eric Niebler is the expert in this area regarding non-nested functions. But if he and others with more knowledge of determining this for free functions would be willing to help me I can certainly look at it in the future. I just do not think it belongs in this particular library as I conceive of it presently.
I think i has one in my previous attempt at this kind of library but it didnt make its way to my github. Th trick I used was to define a function with the same name in the global namespace which prototype being: non_found_type Name( ... ); // Actual ellipsis As f(...) is the last resort in there of overload, testing calling Name( some args ) and checking the return type was not not_found_type, you know if Ret Name(Tn....) exists as a free function.

On 7/5/2011 12:17 PM, Joel falcou wrote:
On 05/07/11 10:35, Edward Diener wrote:
2) Further to the above, I wonder if it's worthwhile providing a set of "standard" introspection classes for the common cases, a straw man list would be something like:
Types: type, value_type, size_type, difference_type, iterator, const_iterator, pointer, const_pointer, reference, const_reference. Static Values: value Functions: begin(), end(), swap(self_type)
That can be easily done once it is determined what to cover.
metafunctions for preexisting concepts could be nice. Bonsu point if they live in a tti/std/???.hpp set of files.
Basically w/e testing for Container, Range and other common concepts should be enough.
I'm also thinking that what folks really want to know is: "Is there a function named X, that can be called with arguments of types A, B and C". It would be interesting to see how far along this road we could actually get?
I think Eric Niebler is the expert in this area regarding non-nested functions. But if he and others with more knowledge of determining this for free functions would be willing to help me I can certainly look at it in the future. I just do not think it belongs in this particular library as I conceive of it presently.
I think i has one in my previous attempt at this kind of library but it didnt make its way to my github. Th trick I used was to define a function with the same name in the global namespace which prototype being:
non_found_type Name( ... ); // Actual ellipsis
As f(...) is the last resort in there of overload, testing calling Name( some args ) and checking the return type was not not_found_type, you know if Ret Name(Tn....) exists as a free function.
I did realize this but as I remember there were some other issues of function detection which Eric Niebler had solved.

On 7/5/2011 4:38 AM, John Maddock wrote:
OK here's my review of this library. snipped...
12) Testing BOOST_TTI_HAS_COMP_MEMBER_FUNCTION(begin)
I see that this static assertion fails:
BOOST_STATIC_ASSERT((boost::tti::has_comp_member_function_begin<std::vector<int>::const_iterator (std::vector<int>::*const)(void)>::value));
Investigating this I find out that the form that function_types generates, which is what BOOST_TTI_HAS_MEMBER_FUNCTION uses, is: std::vector<int>::const_iterator (std::vector<int>::* )() const so that: BOOST_STATIC_ASSERT((boost::tti::has_comp_member_function_begin<std::vector<int>::const_iterator (std::vector<int>::*)(void) const>::value)); does indeed work. It does seem as if putting the 'const' at the end is the correct signature whereas putting it where you originally had it suggests a const member function pointer and not a member function pointer to a const member function.
Have I done something silly? Testing const-member functions seems OK with BOOST_TTI_HAS_MEMBER_FUNCTION BTW.
All the more reason to use the mpl sequence form rather than the composite form unless there is really a need for the composite form with some sort of arcane calling convention or compiler-specific syntax. That's just my opinion of course and I am glad to supply both forms.

BOOST_STATIC_ASSERT((boost::tti::has_comp_member_function_begin<std::vector<int>::const_iterator (std::vector<int>::*)(void) const>::value));
does indeed work.
It does seem as if putting the 'const' at the end is the correct signature whereas putting it where you originally had it suggests a const member function pointer and not a member function pointer to a const member function.
In other words I *was* doing something silly ;-) Thanks, John.

On 7/6/2011 4:00 AM, John Maddock wrote:
BOOST_STATIC_ASSERT((boost::tti::has_comp_member_function_begin<std::vector<int>::const_iterator
(std::vector<int>::*)(void) const>::value));
does indeed work.
It does seem as if putting the 'const' at the end is the correct signature whereas putting it where you originally had it suggests a const member function pointer and not a member function pointer to a const member function.
In other words I *was* doing something silly ;-)
I guess so but it was hard to catch visually. I did not see it until I could compare what worked and what did not through a BOOST_MPL_ASSERT((boost::is_same(mf1::type,mf2::type))) test of the results of the two generated metafuncions.

Please explicitly state in your review whether the library should be accepted.
YES, this library should be accepted after some issues are solved.
- What is your evaluation of the design?
The names of include files are not easy to remember because they are not fully conformant to the macro name (sometimes yes, sometimes not): - HAS_TYPE is in type.hpp - HAS_TEMPLATE is in template.hpp - HAS_TEMPLATE_CHECK_PARAMS is in template_params.hpp -> template_check_params.hpp? - HAS_MEMBER_DATA is in mem_data.hpp -> member_data.hpp? - HAS_MEMBER_FUNCTION is in mem_fun.hpp -> member_function.hpp? I would use the lower case version of the macro with BOOST_TTI_HAS_ removed so that it is easy to remember. I agree with others that traits should be generated in the local namespace instead of boost::tti. Then the user has full control of name clash.
- What is your evaluation of the implementation?
I have not been in detail in the implementation. Just opening some files and this is what came out: can you remove trailing spaces?
- What is your evaluation of the documentation?
- simple examples should appear very early in the doc. You could maybe add a tutorial section starting with the simplest examples, leaving the more complex to the end. You should also give an application example of the trait itself. for example (untested): template <class T, bool Has_a=has_member_data<a, int>::value> void print(const T&); template <class T> void print<T, true>(const T &t) { std::cout<<t.a<<'\n'; } template <class T> void print<T, false>(const T&) { } - Table 1.2. . TTI Macro Metafunctions, it is not clear what means "Type with check". . You could add < T > or < T, U > after the trait name (for example boost::tti::has_type_'name' < T >). . BOOST_TTI_HAS_TEMPLATE, BOOST_TTI_VM_HAS_TEMPLATE_CHECK_PARAMS and BOOST_TTI_HAS_TEMPLATE_CHECK_PARAMS: not clear from the table what it checks for. Is there a class inside T that is declared templaste < typename... > name? What if the enclosing type is itself a template but not the inner type. In that case, the inner type is still a template. - the documentation of for each macro is too succinct. You should re-explain the naming convention that will be used by the macro to create the new trait. You could even just give the C++ code that will be produced by the macro (just the visible code): BOOST_TTI_HAS_TYPE(name) is equivalent to: template < typename T, typename U=notype > struct has_type_name { const bool value; }; with value ... In particular, examples are required for each of them. - examples in tti_usingNTM.html In general, I think simple examples miss. Complex examples are given but simple not. For example, for has_type, I quote: "Does T have a nested type called 'DType' within 'BType::CType' ? BOOST_TTI_HAS_TYPE(DType) boost::tti::mf_has_type < boost::tti::has_type_DType<_>, CTypeNM
We could just have easily used the boost::tti::mf_valid_member_type metafunction to the same effect: boost::tti::mf_valid_member_type < DTypeNM
"
I would be happy to see simple examples like the following: BOOST_TTI_HAS_TYPE(B) BOOST_TTI_HAS_TYPE(mytrait, B) struct A { struct B { } }; boost::tti::has_type_B<A>::value; // true boost::tti::has_type_B<int>::value; // false boost::tti::has_type_B<B>::value; // false boost::tti::mytrait<A>::value; // true boost::tti::mytrait<int>::value; // false boost::tti::mytrait<B>::value; // false - typos: . in tti_detail.html: "will tell use" -> "will tell us" or "will tell the user" . in tti_nested_type.html: "The goal of the TTI library is never to produce a compiler" -> "The goal of the TTI library is to never produce a compiler" - I have seen no explanation of the implementation behavior with regards to public/protected/private category of inner type/member. Could give details in the documentation? I imagine there is no need to introspect private/protected types/members. But what happens if the type/member exists but is private? Compilation error or value==false returned? By the way, I have seen that this is currently not tested as all data and types are public in the tests (in structs). I have tested the following program: #include <iostream> #include <boost/tti/type.hpp> #include <boost/tti/mem_data.hpp> class A { private: class private_type { }; int private_data; protected: class protected_type { }; int protected_data; public: class public_type { }; int public_data; }; BOOST_TTI_HAS_TYPE(private_type) BOOST_TTI_HAS_TYPE(protected_type) BOOST_TTI_HAS_TYPE(public_type) BOOST_TTI_HAS_MEMBER_DATA(private_data) BOOST_TTI_HAS_MEMBER_DATA(protected_data) BOOST_TTI_HAS_MEMBER_DATA(public_data) int main() { std::cout<<boost::tti::has_type_private_type<A>::value<<'\n'; // true std::cout<<boost::tti::has_type_protected_type<A>::value<<'\n'; // true std::cout<<boost::tti::has_type_public_type<A>::value<<'\n'; // true std::cout<<boost::tti::has_member_data_private_data<A, int>::value<<'\n'; // compile time error std::cout<<boost::tti::has_member_data_protected_data<A, int>::value<<'\n'; // compile time error std::cout<<boost::tti::has_member_data_public_data<A, int>::value<<'\n'; // true return 0; } has_type answers true for private, protected and public member types but has_member_data fails to compile if the data member is private of protected (tested with g++ 4.4.4 (log attached). I do not know if this is possible or not but I think the behavior should be: - private or protected -> value==false even if the type/member exists - public -> value==true because private and protected are implementation details which should be ignored. For example what is the need to know if member m of type double exists? probably to use m somewhere. But if m is private, the fact that m exists does not help very much.
- What is your evaluation of the potential usefulness of the library?
I am sure that it can be usefull to implement the best algorithms to appropriate types. For example, you can imagine that adding an element at the front of a container could be specialized for containers that have member function push_front by using it and for other containers by using more complex copying algorithm. Then the best algorithm is used tranparently to the final user.
- Did you try to use the library? With what compiler? Did you have any problems?
Yes, I tried to use the library with g++ 4.4.4. It worked as expected apart for private members as reported (tested HAS_TYPE and HAS_MEMBER_DATA). I ran tests with intel 11 and 12 which failed but the author is dealing with this. I ran tests with g++ 4.4.4 and nothing failed (tested tti target only).
- How much effort did you put into your evaluation? A glance? A quick reading? In-depth study?
I read the doc + some testing (about 4 hours).
- Are you knowledgeable about the problem domain?
I am a bit aware of metaprogramming as I am trying to add an extension to the type trait library for detecting existence of operators.
And finally, every review should answer this question:
- Do you think the library should be accepted as a Boost library?
YES. Frédéric
participants (9)
-
Edward Diener
-
Frédéric Bron
-
Joel falcou
-
Joel Falcou
-
John Bytheway
-
John Maddock
-
Mathias Gaunard
-
Phil Endecott
-
Steven Watanabe