
Review of Boost.TTI 2011-07-10 (Lorenzo Caminiti) ================================================= Do you think the library should be accepted as a Boost library? --------------------------------------------------------------- Yes, in my opinion Boost.TTI should be accepted as a Boost library. Key points are: 1) I would essentially found this library useful as is. 2) The library should not expand its macros into the boost::tti namespace (I give a few reasons and suggest alternatives below). 3) The library uses too many macros to provide essentially the same functionality (with minor variations). This is confusing and the library macro API should be simplified (I suggest a possible simplification below). My comments are all numbered and marked as follow: [MUST] If these comments are not addressed, I would no longer recommend to add this library into Boost. [WANT] I would like to see these comments addressed but I would still recommend to add this library into Boost even if these comments are not addressed. [NOTE] I do not feel strongly about these comments and the authors can ignore these comments if they wish to do so. What is your evaluation of the design? -------------------------------------- 1. [MUST] The library provides too many macros (with very similar functionality) which make the interface difficult to grasp. The authors should take some time to try to redesign and simply the library interface ideally reducing the number of macros. [WANT] I would reduce the macro API to the following 5 macros (no more, as I explain in the rest of the comments below): HAS_TYPE(has_mytype, mytype) HAS_TEMPLATE(has_mytpl, [template(...) {class|struct}] mytpl) HAS_MEMBER_VARIABLE(has_myvar, [static] myvar) HAS_MEMBER_FUNCTION(has_myfunc, [static] myfunc) MEMBER_TYPE(trait, name) 2. [MUST] Expanding the metafunctions within the boost::tti namespace presents a number of serious issues: a) If multiple part of the program (possibly independent libraries) use the TTI library to introspect the same name, the metafunction names will clash. b) The library macros can only be used at namespace scope. However, it should be possible to use the macros also at class scope so to define the introspection metafunctions as inner classes, etc (this is critical for example in my application for Boost.TTI where I use it to implement Boost.Contract and all Boost.Contract macros expand at class scope). The authors should address these issues. [WANT] To address these issues, I would suggest to simply define the metafunctions within the enclosing scope. It will be the user's responsibility to use the macros within the correct scope (namespace, class, etc). For example: template< class T > struct OurTemplateClass { BOOST_TTI_HAS_TYPE(has_mytype, _mytype) // also at class scope void f() { std::cout << has_mytype<T>::value << std::endl; } }; This should also allow to remove all the GEN/GEN_BASE macros. 3. [MUST] The library macros prefix the specified name with _ but this can create a symbol with double underscores __ which is reserved by C++ (e.g., HAS_TYPE(_my_type) creates a metafunction named boost::tti::has_type__my_type which is a reserved symbol). The authors should address this issue. [WANT] To address this issue (and also to reduce the number of macros eliminating the need for separate TRAIT macros), I would suggest to always ask the user to specify both the trait and the introspected name (not just the introspected name) and then use the trait to name the metafunction (as always, it is the user's responsibility to not use reserved names). For example: HAS_TYPE(has_mytype, _mytype) // generates metafunc has_my_type This should also allow to remove all the TRAIT macros. 4. [WANT] I really think that mixing () and <> parenthesis is confusing: HAS_TEMPLATE_CHECK_PARAMS(MoreParameters, (class) (class) (int) (short) (class) (template <class)(int> class InnerTemplate) // confusing :( (class) ) IMO, this would be more readable as the following: HAS_TEMPLATE_CHECK_PARAMS(MoreParameters, (class) (class) (int) (short) (class) (template( (class) (int) ) class InnerTemplate) // ok :) (class) ) 5. [NOTE] There is no real need to use another macro ..._CHECK_PARAMS because HAS_TEMPLATE can be reused. This would reduce the number of macros. For example, with template parameters: HAS_TEMPLATE( template( // gives the parameters (optional) (class) (class) (int) (short) (class) (template( (class) (int) ) class InnerTemplate) (class) ) struct MoreParameters // struct or class can be used here ) And the same macro without template parameters: HAS_TEMPLATE(MoreParameters) 6. [NOTE] The same macros can accept both pp-sequences and variadic pp-tuples (when variadic macros are supported). This eliminates the VM macros reducing the number of different macros in the library API. For example: HAS_TEMPLATE( template( class, class, int, short, class, template( class, int ) class InnerTemplate, // variadic commas class ) struct MoreParameters ) I know this uses template( class, int ) instead of template< class, int > but this way the syntaxes with and without variadics are unified and consistent (and more readable IMO). Alternatively, you can probably program the macro with variadic to be: HAS_TEMPLATE( template< // template< > here class, class, int, short, class, template< class, int > class InnerTemplate, // template< > here class > struct MoreParameters ) But still keep the following syntax without variadics: HAS_TEMPLATE( template( // template( ) here (class) (class) (int) (short) (class) (template( (class) (int) ) class InnerTemplate) // template( ) here (class) ) struct MoreParameters ) 7. [WANT] Can the authors explain why the inner template parameter name InnerTemplate is needed while all other template parameter names are not needed? Is it really needed? Why I cannot do: HAS_TEMPLATE( template( class, class, int, short, class, template( class, int ) class, // no name InnerTemplate class ) struct MoreParameters ) 8. [NOTE] There is no need to use a different set of macros for static because the keyword static can be used to have the pp detect this case. This will reduce the number of different macros. For example: HAS_STATIC_MEMBER_FUNCTION(has_static_f, f) Can be replaced by: HAS_MEMBER_FUNCTION(has_static_f, static f) 9. [WANT] Why can't we always use the composite function syntax R (C::*)(A0, A1, ...)? This is similar to the preferred notation for Boost.Function so if possible it should be used instead of the other notation. As I understand it, some compilers have troubles supporting the composite syntax. However, these compilers might not be able to support the TTI library all together. Unless there is evidence of compilers that can support TTI but not the composite function syntax, I think only the composite function notation should be provided. This should also allow to remove all the COMP macros. 10. [NOTE] I think "member variable" is a more accepted name that "member data"-- isn't it? If so, I'd rename MEMBER_DATA to MEMBER_VARIABLE. 11. [WANT] Is it possible to have some sort of composite syntax for member variables? I remember reading something about this for overloading the operator ->* to access member variables (as well as calling member functions) but I can't double check right now... can the authors look into this? For example: HAS_MEMBER_VARIABLE(has_number, number) has_number<T::short> // composite form for member variable? If there exists a composite form for member variables, I would like the generated metafunctions to use it instead of the plain form (so to be consistent with the MEMBER_FUNCTION macros-- see comment above). 12. [WANT] Are the metafunction MTFC macros really needed? The docs say they reduce compile-time (compared to using MPL placeholders) but no evidence is shown to support that... Extra macros complicate the library API so if they are provided for reducing compile-time there should be some benchmarking showing their benefits. If not, these macros should be removed. [NOTE] If these macros are shown to be beneficial, I'd rename them with a METAFUNC postfix because I find it more readable. For example: HAS_TYPE_METAFUNC HAS_MEMBER_FUNCTION_METAFUNC 13. [WANT] Are the nullary metafunctions really needed? The docs say they simplify the syntax but no side-by-side example comparing the syntax with and without the nullary type metafunctiosn is provided... Unless their benefit is clearly shown, the nullary metafunctions should be remove to simplify the library API. 14. [NOTE] I'd fully spell the header file names to improve readability and be consistent with the macro names (which are correctly fully spelled). For example, "member_function.hpp" instead of "mem_fun.hpp". 15. [NOTE] I'd rather use an actual name for the library instead of the cryptic acronym TTI (but I personally don't like the widely used MPL neither so maybe it's just me). Maybe "intro" (for introspection), or "mirror" (look at yourself), or "soul" (look into your soul), or "psycho" (look into your person) ;) would be better names... What is your evaluation of the implementation? ---------------------------------------------- 16. I did not look at the implementation. What is your evaluation of the documentation? --------------------------------------------- 17. [WANT] I'd add a "Motivating Example" in the Introduction section to very briefly illustrate the library functionality (probably right after the bullet list on the library functionalities). I had to go all the way into the Nested Types section to start seeing some code... (I was motivated just because I knew what the library does and I've used MPL_XXX macros with SFINAE before). 18. [NOTE] I don't think you need a space before "?" in English (see "Why the TTI Library ?", etc). 19. [WANT] Typo in "depending on how many parameters are bring passed". What is your evaluation of the potential usefulness of the library? ------------------------------------------------------------------- 20. [NOTE] The library is very useful as is. For example, I use a similar introspection technique in Boost.Contract as part of a mechanism to check if a base class has a virtual function that is being overridden so to automatically subcontract from such a base class function. 21. [WANT] I think the docs should add an annex with a complete list of all traits that would ideally be introspected even if they cannot actually be introspected. For example, a table could list all traits that would be good to introspect and then for each trait say "introspected by this library", or "cannot be introspected in C++ because...", etc. For example, Boost.Contract could use the ability to check if a function is public, protected, or private to simplify its macro syntax (because only public functions shall check class invariants). Possible traits for introspection I can think of are: is public, is protected, is private, is template, has these template parameters, is explicit, is inline, is extern, is static, is virtual, is const member, is volatile member, has these exception specifications (throw), any more? 22. [WANT] I'd add an annex to the docs to compare this library with other libraries (e.g., the "mirror" library?) that exist out there for introspection (i.e., some sort of literature review). I would also comment on possible C++ standard extensions or compiler specific support for introspection. Did you try to use the library? With what compiler? Did you have any problem? ----------------------------------------------------------------------------- 23. Yes, I compiled all the examples from the docs and played around with the library a bit more. I have used GCC 4.3.4 on CygWin and I had no issue. How much effort did you put into your evaluation? A glance? A quick reading? In-depth study? -------------------------------------------------------------------------------------------- 24. I'd say in between a quick reading and an in-depth study. I spent about 12 hours total reading the docs, trying the examples, and writing this review. Are you knowledgeable about the problem domain? ----------------------------------------------- 25. I have used SFINAE before to introspect if a class has a given inner class to implement subcontracting for Boost.Contract. Furthermore, I have used template metaprogramming in a number of occasions. Overall, I'd say that I am familiar with the problem domain but I am not an expert. --Lorenzo

On 7/10/2011 7:59 PM, Lorenzo Caminiti wrote:
Review of Boost.TTI 2011-07-10 (Lorenzo Caminiti) =================================================
Do you think the library should be accepted as a Boost library? ---------------------------------------------------------------
Yes, in my opinion Boost.TTI should be accepted as a Boost library.
Appreciated !
Key points are:
1) I would essentially found this library useful as is.
2) The library should not expand its macros into the boost::tti namespace (I give a few reasons and suggest alternatives below).
3) The library uses too many macros to provide essentially the same functionality (with minor variations). This is confusing and the library macro API should be simplified (I suggest a possible simplification below).
I will answer each of your points below rather than generally answering 2) or 3) above.
My comments are all numbered and marked as follow: [MUST] If these comments are not addressed, I would no longer recommend to add this library into Boost. [WANT] I would like to see these comments addressed but I would still recommend to add this library into Boost even if these comments are not addressed. [NOTE] I do not feel strongly about these comments and the authors can ignore these comments if they wish to do so.
What is your evaluation of the design? --------------------------------------
1. [MUST] The library provides too many macros (with very similar functionality) which make the interface difficult to grasp. The authors should take some time to try to redesign and simply the library interface ideally reducing the number of macros.
I will give my reasons for each of the macros in answer to your suggestions below, but I completely agree that if the number of macros could be simplified and still offer the same basic functionality it should be done.
[WANT] I would reduce the macro API to the following 5 macros (no more, as I explain in the rest of the comments below):
HAS_TYPE(has_mytype, mytype) HAS_TEMPLATE(has_mytpl, [template(...) {class|struct}] mytpl)
I can look into combining the various template macros if it can be done. Currently there are three variations, disregarding the complex form of each macro. The variations are: BOOST_TTI_HAS_TEMPLATE(name) BOOST_TTI_HAS_TEMPLATE_CHECK_PARAMS(name,pp-seq-of params) BOOST_TTI_VM_HAS_TEMPLATE_CHECK_PARAMS(name,variadic-sequence-of-params) You would like to see a single macro, called BOOST_TTI_HAS_TEMPLATE, which could alternately take a pp-seq-of params or a variadic-sequence-of-params. I agree that would be wonderful if it could be done. To do this the compiler must support variadic macros AFAICS. What if the end-user's compiler does not do so ? Even if the end-user's compiler supports variadic macros, how do I tell the difference between a pp-seq of params and a variadic-sequence of params ? So here are my thoughts. If I supported the single macro for compilers which support variadic macros, I still need to support the two non-variadic macro versions for compilers which do not support variadic macros. For the variadic macro version I can find out that is the variadic-sequence-of-params if it has more than one variadic parameter after the name. If it only has one variadic parameter after the name I can check if the parameter starts with a set of parens and, if it does, it is the pp-seq of params, else it is the variadic-sequence of params. I think this is doable. But I still can not see my way around dropping support completely for the non-variadic versions of this macro.
HAS_MEMBER_VARIABLE(has_myvar, [static] myvar) HAS_MEMBER_FUNCTION(has_myfunc, [static] myfunc)
I can easily combine BOOST_TTI_HAS_MEMBER_DATA and BOOST_TTI_HAS_STATIC_MEMBER_FUNCTION into HAS_MEMBER_VARIABLE, which covers either case, and BOOST_TTI_HAS_MEMBER_FUNCTION and BOOST_TTI_HAS_STATIC_MEMBER_FUNCTION into a HAS_MEMBER_FUNCTION, which cover either case. But then the end-user will lose the ability to distinguish between a 'member data/static member data' or 'member function/static member function'. Do you really think that is the correct thing to do just because you think there are too many macros ? I do not. OTOH I do not mind adding the combined member data and member function macros as you suggested, while keeping what already exists, but then that adds more macros ( which does not bother me a bit ), which you do not like. See below for my comments about the composite type functions.
MEMBER_TYPE(trait, name)
2. [MUST] Expanding the metafunctions within the boost::tti namespace presents a number of serious issues: a) If multiple part of the program (possibly independent libraries) use the TTI library to introspect the same name, the metafunction names will clash. b) The library macros can only be used at namespace scope. However, it should be possible to use the macros also at class scope so to define the introspection metafunctions as inner classes, etc (this is critical for example in my application for Boost.TTI where I use it to implement Boost.Contract and all Boost.Contract macros expand at class scope).
The authors should address these issues.
I totally agree with your criticism here and I will remove the generated macros from any namespace. Others have also mentioned the same thing and I immediately realized they were right when I read their reasoning.
[WANT] To address these issues, I would suggest to simply define the metafunctions within the enclosing scope. It will be the user's responsibility to use the macros within the correct scope (namespace, class, etc). For example:
template< class T> struct OurTemplateClass { BOOST_TTI_HAS_TYPE(has_mytype, _mytype) // also at class scope
void f() { std::cout<< has_mytype<T>::value<< std::endl; } };
This should also allow to remove all the GEN/GEN_BASE macros.
I can remove the GEN_BASE set but I would still keep the GEN set ( which would be the same as the current GEN_BASE set ) in order to provide an easy way to generate the metafunction name from the appropriate macro, without the end-user having to manually remember the algorithm by which I generate the metafunction name. See below for my comments about generating the metafunction name.
3. [MUST] The library macros prefix the specified name with _ but this can create a symbol with double underscores __ which is reserved by C++ (e.g., HAS_TYPE(_my_type) creates a metafunction named boost::tti::has_type__my_type which is a reserved symbol). The authors should address this issue.
You have made a good point and I can simply remove the preceding '_' when generating the final metafunction name.
[WANT] To address this issue (and also to reduce the number of macros eliminating the need for separate TRAIT macros), I would suggest to always ask the user to specify both the trait and the introspected name (not just the introspected name) and then use the trait to name the metafunction (as always, it is the user's responsibility to not use reserved names). For example:
HAS_TYPE(has_mytype, _mytype) // generates metafunc has_my_type
This should also allow to remove all the TRAIT macros.
You want to remove functionality for automatically generating a macro metafunction name just because you feel there are too many macros. I believe that the automatic generation of the metafunction name is welcomed by metaprogrammers. The MPL macros BOOST_MPL_HAS_XXX_TEMPLATE_DEF/BOOST_MPL_HAS_XXX_TEMPLATE_NAMED_DEF and BOOST_MPL_HAS_XXX_TRAIT_DEF/BOOST_MPL_HAS_XXX_TRAIT_NAMED_DEF follow the scheme I have chosen.
4. [WANT] I really think that mixing () and<> parenthesis is confusing:
HAS_TEMPLATE_CHECK_PARAMS(MoreParameters, (class) (class) (int) (short) (class) (template<class)(int> class InnerTemplate) // confusing :( (class) )
IMO, this would be more readable as the following:
HAS_TEMPLATE_CHECK_PARAMS(MoreParameters, (class) (class) (int) (short) (class) (template( (class) (int) ) class InnerTemplate) // ok :) (class) )
I will look into this. It is obviously more difficult programming with the latter than the former, but it is probably doable although with much effort. It may not be worth the effort. What the former syntax reflects is an exact transcription of the template parameters with each comma replaced by ')(' and a starting and ending parentheses. So for the template: 'template <class,class,int,class,template <class> class InnerTemplate,class,long> struct ManyParameters { }' the parameters are: '(class)(class)(int)(class)(template <class> class InnerTemplate)(class)(long)' and all I had to do as an end-user was copy the template parameters, add a '(' at the beginning, add a ')' at the end, and change every ',' to a ')('. As a programmer I take the sequence and directly convert it to the template parameters via a BOOST_PP_SEQ_ENUM.
5. [NOTE] There is no real need to use another macro ..._CHECK_PARAMS because HAS_TEMPLATE can be reused. This would reduce the number of macros. For example, with template parameters:
HAS_TEMPLATE( template( // gives the parameters (optional) (class) (class) (int) (short) (class) (template( (class) (int) ) class InnerTemplate) (class) ) struct MoreParameters // struct or class can be used here )
And the same macro without template parameters:
HAS_TEMPLATE(MoreParameters)
See above for my answer to this.
6. [NOTE] The same macros can accept both pp-sequences and variadic pp-tuples (when variadic macros are supported). This eliminates the VM macros reducing the number of different macros in the library API. For example:
HAS_TEMPLATE( template( class, class, int, short, class, template( class, int ) class InnerTemplate, // variadic commas class ) struct MoreParameters )
I know this uses template( class, int ) instead of template< class, int> but this way the syntaxes with and without variadics are unified and consistent (and more readable IMO). Alternatively, you can probably program the macro with variadic to be:
HAS_TEMPLATE( template< // template< > here class, class, int, short, class, template< class, int> class InnerTemplate, // template< > here class > struct MoreParameters )
But still keep the following syntax without variadics:
HAS_TEMPLATE( template( // template( ) here (class) (class) (int) (short) (class) (template( (class) (int) ) class InnerTemplate) // template( ) here (class) ) struct MoreParameters )
See above for my answer to this.
7. [WANT] Can the authors explain why the inner template parameter name InnerTemplate is needed while all other template parameter names are not needed? Is it really needed? Why I cannot do:
HAS_TEMPLATE( template( class, class, int, short, class, template( class, int ) class, // no name InnerTemplate class ) struct MoreParameters )
It should not be needed. Please try without it. If it does not work I will look and see why and attempt to correct it.
8. [NOTE] There is no need to use a different set of macros for static because the keyword static can be used to have the pp detect this case. This will reduce the number of different macros. For example:
HAS_STATIC_MEMBER_FUNCTION(has_static_f, f)
Can be replaced by:
HAS_MEMBER_FUNCTION(has_static_f, static f)
See above for my previous discussion on dropping the distinction between member functions and static member functions.
9. [WANT] Why can't we always use the composite function syntax R (C::*)(A0, A1, ...)? This is similar to the preferred notation for Boost.Function so if possible it should be used instead of the other notation.
As I understand it, some compilers have troubles supporting the composite syntax. However, these compilers might not be able to support the TTI library all together. Unless there is evidence of compilers that can support TTI but not the composite function syntax, I think only the composite function notation should be provided.
This should also allow to remove all the COMP macros.
The reason for having both a composite syntax, which you like, and the non-composite syntax of individual types is: 1) The composite type syntax can be used when one has to pass a calling convention, or possible some compiler-specified function-like syntax, which the function_types 'tag' type does not support. I think this is absolutely necessary to have. 2) The individual type syntax is there so that MEMBER_TYPE can be used to pass a nested type which does not have to exist without causing a compiler error. I also thin this is absolutely necessary to have. Please read the section called 'Nested Types' in the documentation to understand why MEMBER_TYPE is used. The ability to pass a nested type in the form of a MEMBER_TYPE as a function parameter is very important piece of functionality. Being able to do this for a function parameter type or for the function return type is something I do not want to eliminate.
10. [NOTE] I think "member variable" is a more accepted name that "member data"-- isn't it? If so, I'd rename MEMBER_DATA to MEMBER_VARIABLE.
I can understand your preference. I will consider it.
11. [WANT] Is it possible to have some sort of composite syntax for member variables?
There is no reason to have a composite syntax for member variables. A member variable is a single type.
I remember reading something about this for overloading the operator ->* to access member variables (as well as calling member functions) but I can't double check right now... can the authors look into this? For example:
HAS_MEMBER_VARIABLE(has_number, number)
has_number<T::short> // composite form for member variable?
If there exists a composite form for member variables, I would like the generated metafunctions to use it instead of the plain form (so to be consistent with the MEMBER_FUNCTION macros-- see comment above).
12. [WANT] Are the metafunction MTFC macros really needed? The docs say they reduce compile-time (compared to using MPL placeholders) but no evidence is shown to support that...
Extra macros complicate the library API so if they are provided for reducing compile-time there should be some benchmarking showing their benefits. If not, these macros should be removed.
[NOTE] If these macros are shown to be beneficial, I'd rename them with a METAFUNC postfix because I find it more readable. For example:
HAS_TYPE_METAFUNC HAS_MEMBER_FUNCTION_METAFUNC
I supplied them merely as a convenience. In an early mailing list message about the TTI library from Dave Abrahams, before this review, he suggested that passing metafunctions as data as a metafunction class would generally be faster than passing them via placeholder expressions. I do not mind eliminating them if it seen as overkill.
13. [WANT] Are the nullary metafunctions really needed?
Functionally, no, which the documentation explicitly explains. Syntactically I feel they are much easier to use once they are understood.
The docs say they simplify the syntax but no side-by-side example comparing the syntax with and without the nullary type metafunctiosn is provided...
Unless their benefit is clearly shown, the nullary metafunctions should be remove to simplify the library API.
I will add side by side examples showing the simpler syntax of using the nullary metafunctions. I do show the different syntaxes for similar situations in the doc, but not side by side. Why not just ignore them if you do not like their syntax ? After all tghey are just a set of metafunctions, which no one has to learn to use if they do not want to do so. They do not interfere with anything else in the library and they allow specifying nested types in a syntactically easier way.
14. [NOTE] I'd fully spell the header file names to improve readability and be consistent with the macro names (which are correctly fully spelled). For example, "member_function.hpp" instead of "mem_fun.hpp".
I can do that, and probably will. You have a good point.
15. [NOTE] I'd rather use an actual name for the library instead of the cryptic acronym TTI (but I personally don't like the widely used MPL neither so maybe it's just me). Maybe "intro" (for introspection), or "mirror" (look at yourself), or "soul" (look into your soul), or "psycho" (look into your person) ;) would be better names...
Where would you like to see the longer name ? I certainly do not mind calling the library Type Traits Introspection but that is quite a mouthful. Like MPL ( for Metaprogramming Library ), TTI is easier to remember and refer to.
What is your evaluation of the implementation? ----------------------------------------------
16. I did not look at the implementation.
What is your evaluation of the documentation? ---------------------------------------------
17. [WANT] I'd add a "Motivating Example" in the Introduction section to very briefly illustrate the library functionality (probably right after the bullet list on the library functionalities). I had to go all the way into the Nested Types section to start seeing some code... (I was motivated just because I knew what the library does and I've used MPL_XXX macros with SFINAE before).
I totally agree with you. I intend to revamp the introductory material to make it simpler and easier to understand what the library can do, and present some basic motivating examples.
18. [NOTE] I don't think you need a space before "?" in English (see "Why the TTI Library ?", etc).
You are right. I will change it. It is just my style but unnecessary.
19. [WANT] Typo in "depending on how many parameters are bring passed".
Corrected ! Thanks !
What is your evaluation of the potential usefulness of the library? -------------------------------------------------------------------
20. [NOTE] The library is very useful as is. For example, I use a similar introspection technique in Boost.Contract as part of a mechanism to check if a base class has a virtual function that is being overridden so to automatically subcontract from such a base class function.
21. [WANT] I think the docs should add an annex with a complete list of all traits that would ideally be introspected even if they cannot actually be introspected. For example, a table could list all traits that would be good to introspect and then for each trait say "introspected by this library", or "cannot be introspected in C++ because...", etc. For example, Boost.Contract could use the ability to check if a function is public, protected, or private to simplify its macro syntax (because only public functions shall check class invariants).
Possible traits for introspection I can think of are: is public, is protected, is private, is template, has these template parameters, is explicit, is inline, is extern, is static, is virtual, is const member, is volatile member, has these exception specifications (throw), any more?
I think your possible list is too arbitrary. Most anything can be added here.
22. [WANT] I'd add an annex to the docs to compare this library with other libraries (e.g., the "mirror" library?) that exist out there for introspection (i.e., some sort of literature review).
if there were an existing Boost library I might do it.
I would also comment on possible C++ standard extensions or compiler specific support for introspection.
Which C++ standard ( 2003 or C++0x ) ? For the latter I still have much to learn since it is so new.
Did you try to use the library? With what compiler? Did you have any problem? -----------------------------------------------------------------------------
23. Yes, I compiled all the examples from the docs and played around with the library a bit more. I have used GCC 4.3.4 on CygWin and I had no issue.
How much effort did you put into your evaluation? A glance? A quick reading? In-depth study? --------------------------------------------------------------------------------------------
24. I'd say in between a quick reading and an in-depth study. I spent about 12 hours total reading the docs, trying the examples, and writing this review.
Are you knowledgeable about the problem domain? -----------------------------------------------
25. I have used SFINAE before to introspect if a class has a given inner class to implement subcontracting for Boost.Contract. Furthermore, I have used template metaprogramming in a number of occasions.
Overall, I'd say that I am familiar with the problem domain but I am not an expert.
--Lorenzo
Thanks very much for your review and specific comments. Eddie Diener

On 7/10/2011 7:59 PM, Lorenzo Caminiti wrote:
HAS_MEMBER_VARIABLE(has_myvar, [static] myvar) HAS_MEMBER_FUNCTION(has_myfunc, [static] myfunc)
I can easily combine BOOST_TTI_HAS_MEMBER_DATA and BOOST_TTI_HAS_STATIC_MEMBER_FUNCTION into HAS_MEMBER_VARIABLE, which covers either case, and BOOST_TTI_HAS_MEMBER_FUNCTION and BOOST_TTI_HAS_STATIC_MEMBER_FUNCTION into a HAS_MEMBER_FUNCTION, which cover either case. But then the end-user will lose the ability to distinguish between a 'member data/static member data' or 'member function/static member function'. Do you really think that is the correct thing to do just because you think there are too many macros ? I do not.
I think Lorenzo was suggesting having a single macro whose implementation checks whether the second argument starts with the token "static"; if so it performs a check for static functions only, otherwise it performs a check for nonstatic functions only. Checking whether a macro argument starts with a particular token is certainly doable; see for example [1]. Regards, Nate. [1] http://lists.boost.org/boost-users/2011/03/66612.php

On 7/11/2011 3:26 AM, Nathan Ridge wrote:
On 7/10/2011 7:59 PM, Lorenzo Caminiti wrote:
HAS_MEMBER_VARIABLE(has_myvar, [static] myvar) HAS_MEMBER_FUNCTION(has_myfunc, [static] myfunc)
I can easily combine BOOST_TTI_HAS_MEMBER_DATA and BOOST_TTI_HAS_STATIC_MEMBER_FUNCTION into HAS_MEMBER_VARIABLE, which covers either case, and BOOST_TTI_HAS_MEMBER_FUNCTION and BOOST_TTI_HAS_STATIC_MEMBER_FUNCTION into a HAS_MEMBER_FUNCTION, which cover either case. But then the end-user will lose the ability to distinguish between a 'member data/static member data' or 'member function/static member function'. Do you really think that is the correct thing to do just because you think there are too many macros ? I do not.
I think Lorenzo was suggesting having a single macro whose implementation checks whether the second argument starts with the token "static"; if so it performs a check for static functions only, otherwise it performs a check for nonstatic functions only.
Thanks for clarifying what Lorenzo meant. It does seem to me that using 'static' in front of the variable or function name is not as clear as simply having two different macro names. My current solution is: BOOST_TTI_HAS_MEMBER_FUNCTION(name) BOOST_TTI_HAS_STATIC_MEMBER_FUNCTION(name) Lorenzo's suggested solution: BOOST_TTI_HAS_MEMBER_FUNCTION([static] name) Do you really think that the second solution is better ?
Checking whether a macro argument starts with a particular token is certainly doable; see for example [1].
Yes I already know it is doable with the restricted input of a C++ identifier for the name.

On 10/07/11 22:59, Edward Diener wrote:
I will look into this. It is obviously more difficult programming with the latter than the former, but it is probably doable although with much effort. It may not be worth the effort.
What the former syntax reflects is an exact transcription of the template parameters with each comma replaced by ')(' and a starting and ending parentheses. So for the template:
'template <class,class,int,class,template <class> class InnerTemplate,class,long> struct ManyParameters { }'
the parameters are:
'(class)(class)(int)(class)(template <class> class InnerTemplate)(class)(long)'
and all I had to do as an end-user was copy the template parameters, add a '(' at the beginning, add a ')' at the end, and change every ',' to a ')('. As a programmer I take the sequence and directly convert it to the template parameters via a BOOST_PP_SEQ_ENUM.
Dunno if it helps but nt2 has a NT2_STRIP macro adapted from a amcro pasoted by Steven Watanabe that conditionnally remove parens around symbols. You can then pass parameters containing comma to the preprocessor this way : FOO( (template<class T, class U> struct foo) ) and this way if no comma is involved FOO( struct bar ) THe cod eis available under Boost licensing and can be incorporated w/e your need.

On 7/11/2011 10:12 AM, Joel falcou wrote:
On 10/07/11 22:59, Edward Diener wrote:
I will look into this. It is obviously more difficult programming with the latter than the former, but it is probably doable although with much effort. It may not be worth the effort.
What the former syntax reflects is an exact transcription of the template parameters with each comma replaced by ')(' and a starting and ending parentheses. So for the template:
'template <class,class,int,class,template <class> class InnerTemplate,class,long> struct ManyParameters { }'
the parameters are:
'(class)(class)(int)(class)(template <class> class InnerTemplate)(class)(long)'
and all I had to do as an end-user was copy the template parameters, add a '(' at the beginning, add a ')' at the end, and change every ',' to a ')('. As a programmer I take the sequence and directly convert it to the template parameters via a BOOST_PP_SEQ_ENUM.
Dunno if it helps but nt2 has a NT2_STRIP macro adapted from a amcro pasoted by Steven Watanabe that conditionnally remove parens around symbols.
I already know about this ( Mathias Gaunard reminded me ), and have added it to a possible future implementation for pp-lib. The implementation needs variadic macro support.
You can then pass parameters containing comma to the preprocessor this way :
FOO( (template<class T, class U> struct foo) )
and this way if no comma is involved
FOO( struct bar )
As long as one has variadic macro support in the compiler this can be handled, in which case: FOO( template<class T, class U> struct foo ) is also possible. The issue I brought up in my answer to Lorenzo's review remains the same: do I drop support for a macro metafunction in TTI if the compiler does not have variadic macro support ?

See : https://github.com/MetaScale/nt2/blob/master/modules/sdk/include/nt2/sdk/det... for the file, line 85 and after. The point is it works without variadics and dont clutter the macro call too much. Asking for double parens instead of spitting on , is maybe easier

On 7/11/2011 2:45 PM, Joel falcou wrote:
See :
https://github.com/MetaScale/nt2/blob/master/modules/sdk/include/nt2/sdk/det...
for the file, line 85 and after.
The point is it works without variadics
Line 87: #define NT2_PP_DETAILS_STRIP_PARENS_I(...) 1,1 Line 91: #define NT2_PP_DETAILS_TEST_ARITY_I(a,b,c,...) c Line 96: #define NT2_PP_DETAILS_MAYBE_STRIP_PARENS_2_I(...) __VA_ARGS__ Clearly it needs variadic macro support. I have already added a REMOVE_PARENS ( the equivalent to NT2_PP_STRIP(X) in your URL above ) to a proposed addition to pp-lib which I am discussing with Paul Mensonides, based on the updated variadic macro support on which both of us worked and which is now in the Boost trunk. My point is also that I may well be able to simplify the BOOST_TTI_TEMPLATE macros in TTI using variadic macro support techniques, as Lorenzo suggested, but I do not feel correct in dropping macro support support for compilers which do not support variadic macros although I understand there are few of them left. Eddie

Edward Diener-3 wrote:
On 7/11/2011 2:45 PM, Joel falcou wrote:
See :
https://github.com/MetaScale/nt2/blob/master/modules/sdk/include/nt2/sdk/det...
for the file, line 85 and after.
The point is it works without variadics
Line 87: #define NT2_PP_DETAILS_STRIP_PARENS_I(...) 1,1 Line 91: #define NT2_PP_DETAILS_TEST_ARITY_I(a,b,c,...) c Line 96: #define NT2_PP_DETAILS_MAYBE_STRIP_PARENS_2_I(...) __VA_ARGS__
Clearly it needs variadic macro support.
I have already added a REMOVE_PARENS ( the equivalent to NT2_PP_STRIP(X) in your URL above ) to a proposed addition to pp-lib which I am discussing with Paul Mensonides, based on the updated variadic macro support on which both of us worked and which is now in the Boost trunk.
My point is also that I may well be able to simplify the BOOST_TTI_TEMPLATE macros in TTI using variadic macro support techniques, as Lorenzo suggested, but I do not feel correct in dropping macro support support for compilers which do not support variadic macros although I understand there are few of them left.
I will later reply to all your comments on my review but let me quickly clarify a couple of things. My suggestion was to have the *same* macro TTI_TEMPLATE handle *both* variadics tupletes and sequences. The pp skeleton code will go something like: #if VARIADICS #define TTI_TEMPLATE_VA_(...) \ TTI_TEMPLATE_SEQ_(VA_TUPLE_TO_SEQ(__VA_ARGS__)) #define TTI_TEMPLATE(...) \ BOOST_PP_IIF(IS_VARIADIC(__VA_ARGS__), \ TTI_TEMPLATE_VA_ \ , \ TTI_TEMPLATE_SEQ_ \ )(__VA_ARGS__) #else // variadics #define TTI_TEMPLATE(seq) TTI_TEMPLATE_SEQ_(seq) #endif // variadics Take a look at BOOST_LOCAL_FUNCTION_PARAMS at: http://svn.boost.org/svn/boost/sandbox/local/boost/local/function.hpp This macro could be expanded to also detect a single token and accept the trait parameters in front. The full grammar will then read something like: TTI_TEMPLATE(trait, [tpl_signature_ {class | struct }] name) If the compiler supports variadics: tpl_signature_: tpl_signature_va_ | tpl_signature_seq_ // you can use either variadics or sequences :) If not: tpl_signature_: tpl_signature_seq_ // you must use sequences (because variadiacs are not supported) Where: tpl_signature_seq_: template( (class | typename | type_identifier | tpl_signature_seq_) ... ) // the pp-seq tpl_signature_va_: template< {class | typename | type_identifier | tpl_signature_seq_} ...
// the pp-variadic tuple
Where lexical conventions are: [token] := token is optional token1 | token 2 := either token1 or token2 {expr} := the token(s) resulting from the inner expression epxr (tokens) ... := repeat tokens within parenthesis one or more times (tokens) (tokens) etc tokens ... := repeat tokens separated by commas one or more times tokens, tokens etc I think this should be possible but usually the devil is in the details... so I don't know unless someone tries to implement it :) The real question still stands: Would this be a better interface for TTI_TEMPLATE? (You know my opinion is yes, but that's just my opinion.) Please ask questions and let me know if I am not able to explain myself. --Lorenzo -- View this message in context: http://boost.2283326.n4.nabble.com/TTI-Review-tp3658414p3660843.html Sent from the Boost - Dev mailing list archive at Nabble.com.

On 7/11/2011 5:02 PM, lcaminiti wrote:
Edward Diener-3 wrote:
On 7/11/2011 2:45 PM, Joel falcou wrote:
See :
https://github.com/MetaScale/nt2/blob/master/modules/sdk/include/nt2/sdk/det...
for the file, line 85 and after.
The point is it works without variadics
Line 87: #define NT2_PP_DETAILS_STRIP_PARENS_I(...) 1,1 Line 91: #define NT2_PP_DETAILS_TEST_ARITY_I(a,b,c,...) c Line 96: #define NT2_PP_DETAILS_MAYBE_STRIP_PARENS_2_I(...) __VA_ARGS__
Clearly it needs variadic macro support.
I have already added a REMOVE_PARENS ( the equivalent to NT2_PP_STRIP(X) in your URL above ) to a proposed addition to pp-lib which I am discussing with Paul Mensonides, based on the updated variadic macro support on which both of us worked and which is now in the Boost trunk.
My point is also that I may well be able to simplify the BOOST_TTI_TEMPLATE macros in TTI using variadic macro support techniques, as Lorenzo suggested, but I do not feel correct in dropping macro support support for compilers which do not support variadic macros although I understand there are few of them left.
I will later reply to all your comments on my review but let me quickly clarify a couple of things.
My suggestion was to have the *same* macro TTI_TEMPLATE handle *both* variadics tupletes and sequences.
I did understand it, and I am willing to do that, but of course it needs variadic macro support in the compiler. But what do you think I should do if the compiler does not support variadic macros ? The possibilities are: 1) All compilers for which TTI will compile correctly support variadic macros so don't worry about it and do nothing. 2) If the compiler does not support variadic macros, then the particular BOOS_TTI_TEMPLATE macro and functionality can not be used, and this needs to be documented. 3) Along with the the variadic version of BOOST_TTI_TEMPLATE which you suggested, and which in agreeing with you I can indeed implement and have decided to so do ( thanks for the good suggestion ), I will still need separate versions of BOOST_TTI_TEMPLATE and BOOST_TTI_TEMPLATE_CHECK_PARAMS for compilers which do not support variadic macros, possibly with slightly different names. Now you may feel that 1) or 2) are the right ways to look at things, but I am obliged to do 3) even if it adds another macro name ( or two ) for compilers which do not support variadic macros. This still means that I will do as you have suggested for compilers which do support variadic macros. So I hope my choice of 3) satisfies you while still supporting the rare compiler user when variadic macros are not supported. Also please remember that while most compilers support variadic macros, some of them need a compiler switch to be turned on to do so properly, and there are programmers who may not want to use that compiler switch.
The pp skeleton code will go something like:
#if VARIADICS
#define TTI_TEMPLATE_VA_(...) \ TTI_TEMPLATE_SEQ_(VA_TUPLE_TO_SEQ(__VA_ARGS__))
#define TTI_TEMPLATE(...) \ BOOST_PP_IIF(IS_VARIADIC(__VA_ARGS__), \ TTI_TEMPLATE_VA_ \ , \ TTI_TEMPLATE_SEQ_ \ )(__VA_ARGS__)
#else // variadics
#define TTI_TEMPLATE(seq) TTI_TEMPLATE_SEQ_(seq)
#endif // variadics
Take a look at BOOST_LOCAL_FUNCTION_PARAMS at: http://svn.boost.org/svn/boost/sandbox/local/boost/local/function.hpp
This macro could be expanded to also detect a single token and accept the trait parameters in front. The full grammar will then read something like:
TTI_TEMPLATE(trait, [tpl_signature_ {class | struct }] name)
If the compiler supports variadics:
tpl_signature_: tpl_signature_va_ | tpl_signature_seq_ // you can use either variadics or sequences :)
If not:
tpl_signature_: tpl_signature_seq_ // you must use sequences (because variadiacs are not supported)
Where:
tpl_signature_seq_: template( (class | typename | type_identifier | tpl_signature_seq_) ... ) // the pp-seq
tpl_signature_va_: template< {class | typename | type_identifier | tpl_signature_seq_} ...
// the pp-variadic tuple
Where lexical conventions are: [token] := token is optional token1 | token 2 := either token1 or token2 {expr} := the token(s) resulting from the inner expression epxr (tokens) ... := repeat tokens within parenthesis one or more times (tokens) (tokens) etc tokens ... := repeat tokens separated by commas one or more times tokens, tokens etc
I think this should be possible but usually the devil is in the details... so I don't know unless someone tries to implement it :)
The real question still stands: Would this be a better interface for TTI_TEMPLATE? (You know my opinion is yes, but that's just my opinion.)
Please ask questions and let me know if I am not able to explain myself.
I appreciate the code, and logic, but I can work it out for myself. My experience working with Paul Mensonides on variadic macro support for pp-lib has made me a much better macro coder using pp-lib, and I have learned nearly all the good 'tricks'. Eddie

Edward Diener-3 wrote:
On 7/11/2011 5:02 PM, lcaminiti wrote:
Edward Diener-3 wrote:
On 7/11/2011 2:45 PM, Joel falcou wrote:
See :
https://github.com/MetaScale/nt2/blob/master/modules/sdk/include/nt2/sdk/det...
for the file, line 85 and after.
The point is it works without variadics
Line 87: #define NT2_PP_DETAILS_STRIP_PARENS_I(...) 1,1 Line 91: #define NT2_PP_DETAILS_TEST_ARITY_I(a,b,c,...) c Line 96: #define NT2_PP_DETAILS_MAYBE_STRIP_PARENS_2_I(...) __VA_ARGS__
Clearly it needs variadic macro support.
I have already added a REMOVE_PARENS ( the equivalent to NT2_PP_STRIP(X) in your URL above ) to a proposed addition to pp-lib which I am discussing with Paul Mensonides, based on the updated variadic macro support on which both of us worked and which is now in the Boost trunk.
My point is also that I may well be able to simplify the BOOST_TTI_TEMPLATE macros in TTI using variadic macro support techniques, as Lorenzo suggested, but I do not feel correct in dropping macro support support for compilers which do not support variadic macros although I understand there are few of them left.
I will later reply to all your comments on my review but let me quickly clarify a couple of things.
My suggestion was to have the *same* macro TTI_TEMPLATE handle *both* variadics tupletes and sequences.
I did understand it, and I am willing to do that, but of course it needs variadic macro support in the compiler. But what do you think I should do if the compiler does not support variadic macros ? The possibilities are:
I was trying to say for compilers without variaidics (detected by BOOST_NO_VARIADIC_MACROS) you can do: TTI_TEMPLATE(trait, [tpl_signature_seq_ {class | struct}] name) And for compilers with variadics you can do: TTI_TEMPLATE(trait, [{tpl_signature_seq_ | tpl_signature_va_} {class | struct}] name) Can't you? (Am I missing something?)
1) All compilers for which TTI will compile correctly support variadic macros so don't worry about it and do nothing.
2) If the compiler does not support variadic macros, then the particular BOOS_TTI_TEMPLATE macro and functionality can not be used, and this needs to be documented.
3) Along with the the variadic version of BOOST_TTI_TEMPLATE which you suggested, and which in agreeing with you I can indeed implement and have decided to so do ( thanks for the good suggestion ), I will still need separate versions of BOOST_TTI_TEMPLATE and BOOST_TTI_TEMPLATE_CHECK_PARAMS for compilers which do not support variadic macros, possibly with slightly different names.
Now you may feel that 1) or 2) are the right ways to look at things, but I am obliged to do 3) even if it adds another macro name ( or two ) for compilers which do not support variadic macros. This still means that I will do as you have suggested for compilers which do support variadic macros. So I hope my choice of 3) satisfies you while still supporting the rare compiler user when variadic macros are not supported.
Also please remember that while most compilers support variadic macros, some of them need a compiler switch to be turned on to do so properly, and there are programmers who may not want to use that compiler switch.
The pp skeleton code will go something like:
#if VARIADICS
#define TTI_TEMPLATE_VA_(...) \ TTI_TEMPLATE_SEQ_(VA_TUPLE_TO_SEQ(__VA_ARGS__))
#define TTI_TEMPLATE(...) \ BOOST_PP_IIF(IS_VARIADIC(__VA_ARGS__), \ TTI_TEMPLATE_VA_ \ , \ TTI_TEMPLATE_SEQ_ \ )(__VA_ARGS__)
#else // variadics
#define TTI_TEMPLATE(seq) TTI_TEMPLATE_SEQ_(seq)
#endif // variadics
Take a look at BOOST_LOCAL_FUNCTION_PARAMS at: http://svn.boost.org/svn/boost/sandbox/local/boost/local/function.hpp
This macro could be expanded to also detect a single token and accept the trait parameters in front. The full grammar will then read something like:
TTI_TEMPLATE(trait, [tpl_signature_ {class | struct }] name)
If the compiler supports variadics:
tpl_signature_: tpl_signature_va_ | tpl_signature_seq_ // you can use either variadics or sequences :)
If not:
tpl_signature_: tpl_signature_seq_ // you must use sequences (because variadiacs are not supported)
Where:
tpl_signature_seq_: template( (class | typename | type_identifier | tpl_signature_seq_) ... ) // the pp-seq
tpl_signature_va_: template< {class | typename | type_identifier | tpl_signature_seq_} ...
// the pp-variadic tuple
Where lexical conventions are: [token] := token is optional token1 | token 2 := either token1 or token2 {expr} := the token(s) resulting from the inner expression epxr (tokens) ... := repeat tokens within parenthesis one or more times (tokens) (tokens) etc tokens ... := repeat tokens separated by commas one or more times tokens, tokens etc
I think this should be possible but usually the devil is in the details... so I don't know unless someone tries to implement it :)
The real question still stands: Would this be a better interface for TTI_TEMPLATE? (You know my opinion is yes, but that's just my opinion.)
Please ask questions and let me know if I am not able to explain myself.
I appreciate the code, and logic, but I can work it out for myself. My experience working with Paul Mensonides on variadic macro support for pp-lib has made me a much better macro coder using pp-lib, and I have learned nearly all the good 'tricks'.
Sure. BTW, if you end-up taking a look at Boost.Local and see strange things, please let me know (I'm happy to improve/fix my code if needed). Thanks, --Lorenzo -- View this message in context: http://boost.2283326.n4.nabble.com/TTI-Review-tp3658414p3661016.html Sent from the Boost - Dev mailing list archive at Nabble.com.

On 7/11/2011 6:25 PM, lcaminiti wrote:
Edward Diener-3 wrote:
On 7/11/2011 5:02 PM, lcaminiti wrote:
Edward Diener-3 wrote:
On 7/11/2011 2:45 PM, Joel falcou wrote:
See :
https://github.com/MetaScale/nt2/blob/master/modules/sdk/include/nt2/sdk/det...
for the file, line 85 and after.
The point is it works without variadics
Line 87: #define NT2_PP_DETAILS_STRIP_PARENS_I(...) 1,1 Line 91: #define NT2_PP_DETAILS_TEST_ARITY_I(a,b,c,...) c Line 96: #define NT2_PP_DETAILS_MAYBE_STRIP_PARENS_2_I(...) __VA_ARGS__
Clearly it needs variadic macro support.
I have already added a REMOVE_PARENS ( the equivalent to NT2_PP_STRIP(X) in your URL above ) to a proposed addition to pp-lib which I am discussing with Paul Mensonides, based on the updated variadic macro support on which both of us worked and which is now in the Boost trunk.
My point is also that I may well be able to simplify the BOOST_TTI_TEMPLATE macros in TTI using variadic macro support techniques, as Lorenzo suggested, but I do not feel correct in dropping macro support support for compilers which do not support variadic macros although I understand there are few of them left.
I will later reply to all your comments on my review but let me quickly clarify a couple of things.
My suggestion was to have the *same* macro TTI_TEMPLATE handle *both* variadics tupletes and sequences.
I did understand it, and I am willing to do that, but of course it needs variadic macro support in the compiler. But what do you think I should do if the compiler does not support variadic macros ? The possibilities are:
I was trying to say for compilers without variaidics (detected by BOOST_NO_VARIADIC_MACROS) you can do:
TTI_TEMPLATE(trait, [tpl_signature_seq_ {class | struct}] name)
And for compilers with variadics you can do:
TTI_TEMPLATE(trait, [{tpl_signature_seq_ | tpl_signature_va_} {class | struct}] name)
Can't you? (Am I missing something?)
I do not want to stick the tpl-signature as a prefix sequence to the name. It is ugly and confusing. For some reason you like this sort of thing but I find it poor. Furthermore having to extract the template parameters from the 'name' itself may be undoable even with varaiadic macros much less with only non-variadic macros. You have fallen in love with this sort of thing, perhaps because you have had to do something similar your 'local' library, but I will opt for a simpler and clearer way, even if it means a few extra macro names. However, as you suggested, I can do: TTI_TEMPLATE(name,pp-seq-or-variadic-template-parameters) with variadic parameters support, and will look to implement a single macro on that side rather than both TTI_TEMPLATE and TTI_TEMPLATE_CHECK_PARAMS. Eddie

On 7/11/2011 7:03 PM, Edward Diener wrote:
On 7/11/2011 6:25 PM, lcaminiti wrote:
Edward Diener-3 wrote:
On 7/11/2011 5:02 PM, lcaminiti wrote:
Edward Diener-3 wrote:
On 7/11/2011 2:45 PM, Joel falcou wrote:
See :
https://github.com/MetaScale/nt2/blob/master/modules/sdk/include/nt2/sdk/det...
for the file, line 85 and after.
The point is it works without variadics
Line 87: #define NT2_PP_DETAILS_STRIP_PARENS_I(...) 1,1 Line 91: #define NT2_PP_DETAILS_TEST_ARITY_I(a,b,c,...) c Line 96: #define NT2_PP_DETAILS_MAYBE_STRIP_PARENS_2_I(...) __VA_ARGS__
Clearly it needs variadic macro support.
I have already added a REMOVE_PARENS ( the equivalent to NT2_PP_STRIP(X) in your URL above ) to a proposed addition to pp-lib which I am discussing with Paul Mensonides, based on the updated variadic macro support on which both of us worked and which is now in the Boost trunk.
My point is also that I may well be able to simplify the BOOST_TTI_TEMPLATE macros in TTI using variadic macro support techniques, as Lorenzo suggested, but I do not feel correct in dropping macro support support for compilers which do not support variadic macros although I understand there are few of them left.
I will later reply to all your comments on my review but let me quickly clarify a couple of things.
My suggestion was to have the *same* macro TTI_TEMPLATE handle *both* variadics tupletes and sequences.
I did understand it, and I am willing to do that, but of course it needs variadic macro support in the compiler. But what do you think I should do if the compiler does not support variadic macros ? The possibilities are:
I was trying to say for compilers without variaidics (detected by BOOST_NO_VARIADIC_MACROS) you can do:
TTI_TEMPLATE(trait, [tpl_signature_seq_ {class | struct}] name)
And for compilers with variadics you can do:
TTI_TEMPLATE(trait, [{tpl_signature_seq_ | tpl_signature_va_} {class | struct}] name)
Can't you? (Am I missing something?)
I do not want to stick the tpl-signature as a prefix sequence to the name. It is ugly and confusing. For some reason you like this sort of thing but I find it poor. Furthermore having to extract the template parameters from the 'name' itself may be undoable even with varaiadic macros much less with only non-variadic macros.
After thinking about this, and calming down a bit ( my apologies for getting emotional above ), it may be possible, even without variadic macros, to distinguish between: TTI_TEMPLATE(name) and TTI_TEMPLATE((pp-seq) name) as well as extracting both the pp-seq and the name separately from the second form. Still I will probably opt for: TTI_TEMPLATE(name,BOOST_PP_NIL) or TTI_TEMPLATE(name,(pp-seq)) to distinguish between the two for non-variadic macros. I really do not like the idea of prepending the name being looked for with the template parameters in a single macro argument.

On Mon, Jul 11, 2011 at 9:11 PM, Edward Diener <eldiener@tropicsoft.com> wrote:
On 7/11/2011 7:03 PM, Edward Diener wrote:
On 7/11/2011 6:25 PM, lcaminiti wrote:
Edward Diener-3 wrote:
On 7/11/2011 5:02 PM, lcaminiti wrote:
Edward Diener-3 wrote:
On 7/11/2011 2:45 PM, Joel falcou wrote: > > See : > > > https://github.com/MetaScale/nt2/blob/master/modules/sdk/include/nt2/sdk/det... > > > > > for the file, line 85 and after. > > The point is it works without variadics
Line 87: #define NT2_PP_DETAILS_STRIP_PARENS_I(...) 1,1 Line 91: #define NT2_PP_DETAILS_TEST_ARITY_I(a,b,c,...) c Line 96: #define NT2_PP_DETAILS_MAYBE_STRIP_PARENS_2_I(...) __VA_ARGS__
Clearly it needs variadic macro support.
I have already added a REMOVE_PARENS ( the equivalent to NT2_PP_STRIP(X) in your URL above ) to a proposed addition to pp-lib which I am discussing with Paul Mensonides, based on the updated variadic macro support on which both of us worked and which is now in the Boost trunk.
My point is also that I may well be able to simplify the BOOST_TTI_TEMPLATE macros in TTI using variadic macro support techniques, as Lorenzo suggested, but I do not feel correct in dropping macro support support for compilers which do not support variadic macros although I understand there are few of them left.
I will later reply to all your comments on my review but let me quickly clarify a couple of things.
My suggestion was to have the *same* macro TTI_TEMPLATE handle *both* variadics tupletes and sequences.
I did understand it, and I am willing to do that, but of course it needs variadic macro support in the compiler. But what do you think I should do if the compiler does not support variadic macros ? The possibilities are:
I was trying to say for compilers without variaidics (detected by BOOST_NO_VARIADIC_MACROS) you can do:
TTI_TEMPLATE(trait, [tpl_signature_seq_ {class | struct}] name)
And for compilers with variadics you can do:
TTI_TEMPLATE(trait, [{tpl_signature_seq_ | tpl_signature_va_} {class | struct}] name)
Can't you? (Am I missing something?)
I do not want to stick the tpl-signature as a prefix sequence to the name. It is ugly and confusing. For some reason you like this sort of thing but I find it poor. Furthermore having to extract the template parameters from the 'name' itself may be undoable even with varaiadic macros much less with only non-variadic macros.
After thinking about this, and calming down a bit ( my apologies for getting emotional above ), it may be possible, even without variadic macros, to distinguish between:
OK, it looks like we're exchanging messages in real-time here-- I sent you a reply and .5 sec after I got this other message :)
TTI_TEMPLATE(name)
and
TTI_TEMPLATE((pp-seq) name)
as well as extracting both the pp-seq and the name separately from the second form. Still I will probably opt for:
TTI_TEMPLATE(name,BOOST_PP_NIL)
or
TTI_TEMPLATE(name,(pp-seq))
to distinguish between the two for non-variadic macros. I really do not like the idea of prepending the name being looked for with the template parameters in a single macro argument.
I don't think for 1 single macro argument the template prefix is needed (see [1] below). Let's write down some examples for what I meant with comment #5 leaving variadics (comment #6) and implementation issues a side for a moment. Let's just try to see if (1) we understand each other and (2) we list options that users will find to be a better interface for the library. I will not list the trait parameter (even if I suggested to always add it). Here's some examples of what I was proposing with my comment #5: // check if mytpl exist TTI_TEMPLATE( mytpl ) // [1] // check if template<class> struct mytpl exist TTI_TEMPLATE( template( (class) ) struct mytpl ) // check if template<class, int> class mytpl exist TTI_TEMPLATE( template( (class) (int) ) class mytpl ) // check if template<class, int, template<typename, class> struct> class mytpl exist TTI_TEMPLATE( template( (class) (int) (template( (typename) (class) ) struct) class mytpl ) The real question still is: For the TTI library user, is the interface above better than TTI_TEMPLATE_CHECK_PARAMS? (Again, you know my answer is yes but that's just my opinion.) I think we should all focus the discussion in try to answer this question first. Thanks, --Lorenzo

On 7/11/2011 9:32 PM, Lorenzo Caminiti wrote:
On Mon, Jul 11, 2011 at 9:11 PM, Edward Diener<eldiener@tropicsoft.com> wrote:
On 7/11/2011 7:03 PM, Edward Diener wrote:
On 7/11/2011 6:25 PM, lcaminiti wrote:
Edward Diener-3 wrote:
On 7/11/2011 5:02 PM, lcaminiti wrote:
Edward Diener-3 wrote: > > On 7/11/2011 2:45 PM, Joel falcou wrote: >> >> See : >> >> >> https://github.com/MetaScale/nt2/blob/master/modules/sdk/include/nt2/sdk/det... >> >> >> >> >> for the file, line 85 and after. >> >> The point is it works without variadics > > Line 87: #define NT2_PP_DETAILS_STRIP_PARENS_I(...) 1,1 > Line 91: #define NT2_PP_DETAILS_TEST_ARITY_I(a,b,c,...) c > Line 96: #define NT2_PP_DETAILS_MAYBE_STRIP_PARENS_2_I(...) > __VA_ARGS__ > > Clearly it needs variadic macro support. > > I have already added a REMOVE_PARENS ( the equivalent to > NT2_PP_STRIP(X) > in your URL above ) to a proposed addition to pp-lib which I am > discussing with Paul Mensonides, based on the updated variadic macro > support on which both of us worked and which is now in the Boost > trunk. > > My point is also that I may well be able to simplify the > BOOST_TTI_TEMPLATE macros in TTI using variadic macro support > techniques, as Lorenzo suggested, but I do not feel correct in > dropping > macro support support for compilers which do not support variadic > macros > although I understand there are few of them left. >
I will later reply to all your comments on my review but let me quickly clarify a couple of things.
My suggestion was to have the *same* macro TTI_TEMPLATE handle *both* variadics tupletes and sequences.
I did understand it, and I am willing to do that, but of course it needs variadic macro support in the compiler. But what do you think I should do if the compiler does not support variadic macros ? The possibilities are:
I was trying to say for compilers without variaidics (detected by BOOST_NO_VARIADIC_MACROS) you can do:
TTI_TEMPLATE(trait, [tpl_signature_seq_ {class | struct}] name)
And for compilers with variadics you can do:
TTI_TEMPLATE(trait, [{tpl_signature_seq_ | tpl_signature_va_} {class | struct}] name)
Can't you? (Am I missing something?)
I do not want to stick the tpl-signature as a prefix sequence to the name. It is ugly and confusing. For some reason you like this sort of thing but I find it poor. Furthermore having to extract the template parameters from the 'name' itself may be undoable even with varaiadic macros much less with only non-variadic macros.
After thinking about this, and calming down a bit ( my apologies for getting emotional above ), it may be possible, even without variadic macros, to distinguish between:
OK, it looks like we're exchanging messages in real-time here-- I sent you a reply and .5 sec after I got this other message :)
TTI_TEMPLATE(name)
and
TTI_TEMPLATE((pp-seq) name)
as well as extracting both the pp-seq and the name separately from the second form. Still I will probably opt for:
TTI_TEMPLATE(name,BOOST_PP_NIL)
or
TTI_TEMPLATE(name,(pp-seq))
to distinguish between the two for non-variadic macros. I really do not like the idea of prepending the name being looked for with the template parameters in a single macro argument.
I don't think for 1 single macro argument the template prefix is needed (see [1] below).
Let's write down some examples for what I meant with comment #5 leaving variadics (comment #6) and implementation issues a side for a moment. Let's just try to see if (1) we understand each other and (2) we list options that users will find to be a better interface for the library. I will not list the trait parameter (even if I suggested to always add it).
Here's some examples of what I was proposing with my comment #5:
// check if mytpl exist TTI_TEMPLATE( mytpl ) // [1]
// check if template<class> struct mytpl exist TTI_TEMPLATE( template( (class) ) struct mytpl )
// check if template<class, int> class mytpl exist TTI_TEMPLATE( template( (class) (int) ) class mytpl )
// check if template<class, int, template<typename, class> struct> class mytpl exist TTI_TEMPLATE( template( (class) (int) (template( (typename) (class) ) struct) class mytpl )
The real question still is: For the TTI library user, is the interface above better than TTI_TEMPLATE_CHECK_PARAMS? (Again, you know my answer is yes but that's just my opinion.) I think we should all focus the discussion in try to answer this question first.
I do not like your syntax. I much prefer the syntax I already have, with a separate macro parameter merely being the template parameters if the end-user is looking for a match, ie. TTI_TEMPLATE(mytpl,BOOST_PP_NIL) TTI_TEMPLATE(mytpl,(class)(int)(template<typename class> struct)) or for variadic macros TTI_TEMPLATE(mytpl) TTI_TEMPLATE(mytpl,class,int,template<typename class> struct) Eddie

On Mon, Jul 11, 2011 at 10:53 PM, Edward Diener <eldiener@tropicsoft.com> wrote:
On 7/11/2011 9:32 PM, Lorenzo Caminiti wrote:
Let's write down some examples for what I meant with comment #5 leaving variadics (comment #6) and implementation issues a side for a moment. Let's just try to see if (1) we understand each other and (2) we list options that users will find to be a better interface for the library. I will not list the trait parameter (even if I suggested to always add it).
Here's some examples of what I was proposing with my comment #5:
// check if mytpl exist TTI_TEMPLATE( mytpl ) // [1]
// check if template<class> struct mytpl exist TTI_TEMPLATE( template( (class) ) struct mytpl )
// check if template<class, int> class mytpl exist TTI_TEMPLATE( template( (class) (int) ) class mytpl )
// check if template<class, int, template<typename, class> struct> class mytpl exist TTI_TEMPLATE( template( (class) (int) (template( (typename) (class) ) struct) class mytpl )
The real question still is: For the TTI library user, is the interface above better than TTI_TEMPLATE_CHECK_PARAMS? (Again, you know my answer is yes but that's just my opinion.) I think we should all focus the discussion in try to answer this question first.
I do not like your syntax. I much prefer the syntax I already have, with a separate macro parameter merely being the template parameters if the end-user is looking for a match, ie.
TTI_TEMPLATE(mytpl,BOOST_PP_NIL) TTI_TEMPLATE(mytpl,(class)(int)(template<typename class> struct))
or for variadic macros
TTI_TEMPLATE(mytpl) TTI_TEMPLATE(mytpl,class,int,template<typename class> struct)
OK but don't you need something in between the inner template typename and class? (Because they can be any arbitrary type name for non-type template parameters.) For example (again, leaving variadics a side for a moment): TTI_TEMPLATE(mytpl,BOOST_PP_NIL) TTI_TEMPLATE(mytpl,(class)(int)(template<typename)(class> struct)) // [1] If so, is that better than the following? TTI_TEMPLATE(mytpl,BOOST_PP_NIL) TTI_TEMPLATE(mytpl,(class)(int)(template( (typename)(class) ) struct)) // [2] (You know I (somewhat strongly this time) prefer [2] to [1], see my comment #4. But that's just my opinion.) Thanks, --Lorenzo

[I have not looked in detail at the TTI library and only *just* caught up on this email exchange...whew!] On Mon, Jul 11, 2011 at 8:07 PM, Lorenzo Caminiti <lorcaminiti@gmail.com>wrote:
On Mon, Jul 11, 2011 at 10:53 PM, Edward Diener <eldiener@tropicsoft.com> wrote:
[...]
I do not like your syntax. I much prefer the syntax I already have, with a separate macro parameter merely being the template parameters if the end-user is looking for a match, ie.
TTI_TEMPLATE(mytpl,BOOST_PP_NIL) TTI_TEMPLATE(mytpl,(class)(int)(template<typename class> struct))
This is acceptable.
or for variadic macros
TTI_TEMPLATE(mytpl) TTI_TEMPLATE(mytpl,class,int,template<typename class> struct)
Didn't Paul Mensonides (sp? sorry Paul!) rail against such constructs just a week or two ago? :) I.e., shouldn't the template signature be packaged into a single parameter?
OK but don't you need something in between the inner template typename and class? (Because they can be any arbitrary type name for non-type template parameters.) For example (again, leaving variadics a side for a moment):
TTI_TEMPLATE(mytpl,BOOST_PP_NIL) TTI_TEMPLATE(mytpl,(class)(int)(template<typename)(class> struct)) // [1]
If so, is that better than the following?
TTI_TEMPLATE(mytpl,BOOST_PP_NIL) TTI_TEMPLATE(mytpl,(class)(int)(template( (typename)(class) ) struct)) // [2]
(You know I (somewhat strongly this time) prefer [2] to [1], see my comment #4. But that's just my opinion.)
FWIW, I, too, prefer [2] over [1], and I also kind of like Lorenzo's earlier suggested syntax of TTI_TEMPLATE( mytmp ) // template signature unspecified TTI_TEMPLATE( template( ( class ) ( int ) ( template( ( typename ) ( class ) ) ) struct mytmp ) // template signature specified I *might* even go so far as to say that the equivalent variadic version would just replace the Boost.PP Seqs with Boost.PP Tuples, and no more (i.e., still don't use '<'s and '>'s): TTI_TEMPLATE( template( class, int, template( typename, class ) ) struct mytmp ) // variadic version But that might not be a good idea, and, even worse, might be too radical :) - Jeff

On 7/11/2011 11:55 PM, Jeffrey Lee Hellrung, Jr. wrote:
[I have not looked in detail at the TTI library and only *just* caught up on this email exchange...whew!]
On Mon, Jul 11, 2011 at 8:07 PM, Lorenzo Caminiti<lorcaminiti@gmail.com>wrote:
On Mon, Jul 11, 2011 at 10:53 PM, Edward Diener<eldiener@tropicsoft.com> wrote:
[...]
I do not like your syntax. I much prefer the syntax I already have, with a separate macro parameter merely being the template parameters if the end-user is looking for a match, ie.
TTI_TEMPLATE(mytpl,BOOST_PP_NIL) TTI_TEMPLATE(mytpl,(class)(int)(template<typename class> struct))
This is acceptable.
or for variadic macros
TTI_TEMPLATE(mytpl) TTI_TEMPLATE(mytpl,class,int,template<typename class> struct)
Didn't Paul Mensonides (sp? sorry Paul!) rail against such constructs just a week or two ago? :) I.e., shouldn't the template signature be packaged into a single parameter?
I do not know what you are referring to regarding Paul Mensonides' opinion but a large part of variadic macros value, IMO, is that they provide a better syntax for the end-user while the pp-lib data types provide much richer functionality internally. So I see no reason why the variadic macro syntax should not be provided for end-user use.

On Tue, Jul 12, 2011 at 10:23 AM, Edward Diener <eldiener@tropicsoft.com>wrote:
On 7/11/2011 11:55 PM, Jeffrey Lee Hellrung, Jr. wrote:
[I have not looked in detail at the TTI library and only *just* caught up on this email exchange...whew!]
On Mon, Jul 11, 2011 at 8:07 PM, Lorenzo Caminiti<lorcaminiti@gmail.com**
wrote:
On Mon, Jul 11, 2011 at 10:53 PM, Edward Diener<eldiener@tropicsoft.com*
*> wrote:
[...]
I do not like your syntax. I much prefer the syntax I already have, with
a
separate macro parameter merely being the template parameters if the end-user is looking for a match, ie.
TTI_TEMPLATE(mytpl,BOOST_PP_**NIL) TTI_TEMPLATE(mytpl,(class)(**int)(template<typename class> struct))
This is acceptable.
or for variadic macros
TTI_TEMPLATE(mytpl) TTI_TEMPLATE(mytpl,class,int,**template<typename class> struct)
Didn't Paul Mensonides (sp? sorry Paul!) rail against such constructs just a week or two ago? :) I.e., shouldn't the template signature be packaged into a single parameter?
I do not know what you are referring to regarding Paul Mensonides' opinion but a large part of variadic macros value, IMO, is that they provide a better syntax for the end-user while the pp-lib data types provide much richer functionality internally. So I see no reason why the variadic macro syntax should not be provided for end-user use.
Perhaps I'm misinterpreting and/or reading too much into http://article.gmane.org/gmane.comp.lib.boost.devel/221076 e.g., "> BOOST_LOCAL_PARAMS(int x, int& y) // (1) BOOST_LOCAL_PARAMS( (int x) [...] Regardless, I actually believe that the (1) case above is actually a large step *backwards*. It's worse, not better, because it's trying (and failing) to be the underlying language and introducing a bunch of gotchas in the attempt." and subsequent follow-ups, e.g., http://article.gmane.org/gmane.comp.lib.boost.devel/221104 and, if so, let me know, but I read this and think (among other things), wouldn't it be better to package the template signature up into a single parameter? For one thing, this would simplify the use of TTI_TEMPLATE within preprocessor structures, wouldn't it? I'm not saying we can't take advantage of variadic macros, I'm just saying maybe we shouldn't make TTI_TEMPLATE a variadic macro (okay, other than accepting 1 argument, "mytpl", or 2 arguments, "mytpl" and the template signature). - Jeff

On 7/12/2011 4:57 PM, Jeffrey Lee Hellrung, Jr. wrote:
On Tue, Jul 12, 2011 at 10:23 AM, Edward Diener<eldiener@tropicsoft.com>wrote:
On 7/11/2011 11:55 PM, Jeffrey Lee Hellrung, Jr. wrote:
[I have not looked in detail at the TTI library and only *just* caught up on this email exchange...whew!]
On Mon, Jul 11, 2011 at 8:07 PM, Lorenzo Caminiti<lorcaminiti@gmail.com**
wrote:
On Mon, Jul 11, 2011 at 10:53 PM, Edward Diener<eldiener@tropicsoft.com*
*> wrote:
[...]
I do not like your syntax. I much prefer the syntax I already have, with
a
separate macro parameter merely being the template parameters if the end-user is looking for a match, ie.
TTI_TEMPLATE(mytpl,BOOST_PP_**NIL) TTI_TEMPLATE(mytpl,(class)(**int)(template<typename class> struct))
This is acceptable.
or for variadic macros
TTI_TEMPLATE(mytpl) TTI_TEMPLATE(mytpl,class,int,**template<typename class> struct)
Didn't Paul Mensonides (sp? sorry Paul!) rail against such constructs just a week or two ago? :) I.e., shouldn't the template signature be packaged into a single parameter?
I do not know what you are referring to regarding Paul Mensonides' opinion but a large part of variadic macros value, IMO, is that they provide a better syntax for the end-user while the pp-lib data types provide much richer functionality internally. So I see no reason why the variadic macro syntax should not be provided for end-user use.
Perhaps I'm misinterpreting and/or reading too much into
http://article.gmane.org/gmane.comp.lib.boost.devel/221076
e.g.,
"> BOOST_LOCAL_PARAMS(int x, int& y) // (1) BOOST_LOCAL_PARAMS( (int x) [...] Regardless, I actually believe that the (1) case above is actually a large step *backwards*. It's worse, not better, because it's trying (and failing) to be the underlying language and introducing a bunch of gotchas in the attempt."
and subsequent follow-ups, e.g.,
http://article.gmane.org/gmane.comp.lib.boost.devel/221104
and, if so, let me know, but I read this and think (among other things), wouldn't it be better to package the template signature up into a single parameter? For one thing, this would simplify the use of TTI_TEMPLATE within preprocessor structures, wouldn't it? I'm not saying we can't take advantage of variadic macros, I'm just saying maybe we shouldn't make TTI_TEMPLATE a variadic macro (okay, other than accepting 1 argument, "mytpl", or 2 arguments, "mytpl" and the template signature).
I disagree with the idea that variadic macros syntax should not be used by the end-user.

On 7/12/2011 4:57 PM, Jeffrey Lee Hellrung, Jr. wrote:
On Tue, Jul 12, 2011 at 10:23 AM, Edward Diener<eldiener@tropicsoft.com>wrote:
On 7/11/2011 11:55 PM, Jeffrey Lee Hellrung, Jr. wrote:
[I have not looked in detail at the TTI library and only *just* caught up on this email exchange...whew!]
On Mon, Jul 11, 2011 at 8:07 PM, Lorenzo Caminiti<lorcaminiti@gmail.com**
wrote:
On Mon, Jul 11, 2011 at 10:53 PM, Edward Diener<eldiener@tropicsoft.com*
*> wrote:
[...]
I do not like your syntax. I much prefer the syntax I already have, with
a
separate macro parameter merely being the template parameters if the end-user is looking for a match, ie.
TTI_TEMPLATE(mytpl,BOOST_PP_**NIL) TTI_TEMPLATE(mytpl,(class)(**int)(template<typename class> struct))
This is acceptable.
or for variadic macros
TTI_TEMPLATE(mytpl) TTI_TEMPLATE(mytpl,class,int,**template<typename class> struct)
Didn't Paul Mensonides (sp? sorry Paul!) rail against such constructs just a week or two ago? :) I.e., shouldn't the template signature be packaged into a single parameter?
I do not know what you are referring to regarding Paul Mensonides' opinion but a large part of variadic macros value, IMO, is that they provide a better syntax for the end-user while the pp-lib data types provide much richer functionality internally. So I see no reason why the variadic macro syntax should not be provided for end-user use.
Perhaps I'm misinterpreting and/or reading too much into
http://article.gmane.org/gmane.comp.lib.boost.devel/221076
e.g.,
"> BOOST_LOCAL_PARAMS(int x, int& y) // (1) BOOST_LOCAL_PARAMS( (int x) [...] Regardless, I actually believe that the (1) case above is actually a large step *backwards*. It's worse, not better, because it's trying (and failing) to be the underlying language and introducing a bunch of gotchas in the attempt."
and subsequent follow-ups, e.g.,
http://article.gmane.org/gmane.comp.lib.boost.devel/221104
and, if so, let me know, but I read this and think (among other things), wouldn't it be better to package the template signature up into a single parameter?
I wanted to clarify my reaction to Paul's remarks in the URLs you quoted. I agree with him in general that it is better to pass preprocessing tokens as data in pp-lib data structures, since the data normally has a corresponding notion of equivalence to 'data' in C++ or other languages. This is because the pp-lib data structures mimic containers which computer languages use to pass data. But I do not see this as a hard and fast rule, especially when the preprocessing tokens being passed are being treated basically as 'strings' to be concatenated to form a C++ language construct. In that case I see nothing wrong with passing data as just variadic data tokens and accessing the concatenated 'strings' as __VA_ARGS__. This is the case with my design for TTI_HAS_TEMPLATE, where the actual template parameters on which the introspection is occuring are just strings of tokens being passed by the end-user to internally form the template construct which I will be checking in my code.

On 7/11/2011 11:07 PM, Lorenzo Caminiti wrote:
On Mon, Jul 11, 2011 at 10:53 PM, Edward Diener<eldiener@tropicsoft.com> wrote:
On 7/11/2011 9:32 PM, Lorenzo Caminiti wrote:
Let's write down some examples for what I meant with comment #5 leaving variadics (comment #6) and implementation issues a side for a moment. Let's just try to see if (1) we understand each other and (2) we list options that users will find to be a better interface for the library. I will not list the trait parameter (even if I suggested to always add it).
Here's some examples of what I was proposing with my comment #5:
// check if mytpl exist TTI_TEMPLATE( mytpl ) // [1]
// check if template<class> struct mytpl exist TTI_TEMPLATE( template( (class) ) struct mytpl )
// check if template<class, int> class mytpl exist TTI_TEMPLATE( template( (class) (int) ) class mytpl )
// check if template<class, int, template<typename, class> struct> class mytpl exist TTI_TEMPLATE( template( (class) (int) (template( (typename) (class) ) struct) class mytpl )
The real question still is: For the TTI library user, is the interface above better than TTI_TEMPLATE_CHECK_PARAMS? (Again, you know my answer is yes but that's just my opinion.) I think we should all focus the discussion in try to answer this question first.
I do not like your syntax. I much prefer the syntax I already have, with a separate macro parameter merely being the template parameters if the end-user is looking for a match, ie.
TTI_TEMPLATE(mytpl,BOOST_PP_NIL) TTI_TEMPLATE(mytpl,(class)(int)(template<typename class> struct))
or for variadic macros
TTI_TEMPLATE(mytpl) TTI_TEMPLATE(mytpl,class,int,template<typename class> struct)
OK but don't you need something in between the inner template typename and class? (Because they can be any arbitrary type name for non-type template parameters.) For example (again, leaving variadics a side for a moment):
TTI_TEMPLATE(mytpl,BOOST_PP_NIL) TTI_TEMPLATE(mytpl,(class)(int)(template<typename)(class> struct)) // [1]
If so, is that better than the following?
TTI_TEMPLATE(mytpl,BOOST_PP_NIL) TTI_TEMPLATE(mytpl,(class)(int)(template( (typename)(class) ) struct)) // [2]
(You know I (somewhat strongly this time) prefer [2] to [1], see my comment #4. But that's just my opinion.)
There is no reason to prefer replacing '<' and '>' in the syntax for the template parameters with '(' and ')' other than to complicate matters unnecessarily. After thinking about this last night I have decided to use a pp-array instead of a pp-seq as the extended syntax for the non-variadic version and as an alternate syntax for the variadic version. So the syntaxes for TTI_TEMPLATE, using 'template<class,class,class> struct xxx' and using 'template<class,int,template<class,class> > struct yyy' are: TTI_TEMPLATE(xxx,BOOST_PP_NIL) // (1) non-variadic only TTI_TEMPLATE(xxx) // (2) variadic only TTI_TEMPLATE(yyy,(3,(class,int,template<class,class>))) // (3) both TTI_TEMPLATE(yyy,class,int,template<class,class>) // (4) variadic only Using a pp-array allows for the same syntax for specifying the template parameters, without the nonsense of changing the angle brackets to parentheses. I want this to be straightforward for an end-user to use. For the check params case, (3) and (4), they just copy the template parameters from the template for which they are searching and use them. While your idea of putting the entire template for which their are specifically searching in front of the name is externally attractive it has two negatives: 1) The end-user has to create a complicated syntax for the template parameters which does not correspond to how they actually look in the template. 2) It is impossible to parse using non-variadic macros and nearly impossible to parse using variadic macros. While I welcome your arguments, I do not want to keep debating this endlessly. I believe I have come up with a syntax, as illustrated above, which is easy and understandable for the end-user, provides the maximum flexibility for the end-user, is fairly easily programmmable by me, and uses a single macro name for both the variadic and non-variadic versions of the macro.

Edward Diener-3 wrote:
On 7/11/2011 11:07 PM, Lorenzo Caminiti wrote:
On Mon, Jul 11, 2011 at 10:53 PM, Edward Diener<eldiener@tropicsoft.com> wrote:
On 7/11/2011 9:32 PM, Lorenzo Caminiti wrote:
Let's write down some examples for what I meant with comment #5 leaving variadics (comment #6) and implementation issues a side for a moment. Let's just try to see if (1) we understand each other and (2) we list options that users will find to be a better interface for the library. I will not list the trait parameter (even if I suggested to always add it).
Here's some examples of what I was proposing with my comment #5:
// check if mytpl exist TTI_TEMPLATE( mytpl ) // [1]
// check if template<class> struct mytpl exist TTI_TEMPLATE( template( (class) ) struct mytpl )
// check if template<class, int> class mytpl exist TTI_TEMPLATE( template( (class) (int) ) class mytpl )
// check if template<class, int, template<typename, class> struct> class mytpl exist TTI_TEMPLATE( template( (class) (int) (template( (typename) (class) ) struct) class mytpl )
The real question still is: For the TTI library user, is the interface above better than TTI_TEMPLATE_CHECK_PARAMS? (Again, you know my answer is yes but that's just my opinion.) I think we should all focus the discussion in try to answer this question first.
I do not like your syntax. I much prefer the syntax I already have, with a separate macro parameter merely being the template parameters if the end-user is looking for a match, ie.
TTI_TEMPLATE(mytpl,BOOST_PP_NIL) TTI_TEMPLATE(mytpl,(class)(int)(template<typename class> struct))
or for variadic macros
TTI_TEMPLATE(mytpl) TTI_TEMPLATE(mytpl,class,int,template<typename class> struct)
OK but don't you need something in between the inner template typename and class? (Because they can be any arbitrary type name for non-type template parameters.) For example (again, leaving variadics a side for a moment):
TTI_TEMPLATE(mytpl,BOOST_PP_NIL) TTI_TEMPLATE(mytpl,(class)(int)(template<typename)(class> struct)) // [1]
If so, is that better than the following?
TTI_TEMPLATE(mytpl,BOOST_PP_NIL) TTI_TEMPLATE(mytpl,(class)(int)(template( (typename)(class) ) struct)) // [2]
(You know I (somewhat strongly this time) prefer [2] to [1], see my comment #4. But that's just my opinion.)
There is no reason to prefer replacing '<' and '>' in the syntax for the template parameters with '(' and ')' other than to complicate matters unnecessarily.
After thinking about this last night I have decided to use a pp-array instead of a pp-seq as the extended syntax for the non-variadic version and as an alternate syntax for the variadic version. So the syntaxes for TTI_TEMPLATE,
using 'template<class,class,class> struct xxx' and using 'template<class,int,template<class,class> > struct yyy' are:
TTI_TEMPLATE(xxx,BOOST_PP_NIL) // (1) non-variadic only TTI_TEMPLATE(xxx) // (2) variadic only TTI_TEMPLATE(yyy,(3,(class,int,template<class,class>))) // (3) both TTI_TEMPLATE(yyy,class,int,template<class,class>) // (4) variadic only
Using a pp-array allows for the same syntax for specifying the template parameters, without the nonsense of changing the angle brackets to parentheses.
I want this to be straightforward for an end-user to use. For the check params case, (3) and (4), they just copy the template parameters from the template for which they are searching and use them.
While your idea of putting the entire template for which their are specifically searching in front of the name is externally attractive it has two negatives:
1) The end-user has to create a complicated syntax for the template parameters which does not correspond to how they actually look in the template.
2) It is impossible to parse using non-variadic macros and nearly
What is the issue that makes it impossible? Can you show me an example?
impossible to parse using variadic macros.
While I welcome your arguments, I do not want to keep debating this endlessly. I believe I have come up with a syntax, as illustrated above, which is easy and understandable for the end-user, provides the maximum flexibility for the end-user, is fairly easily programmmable by me, and uses a single macro name for both the variadic and non-variadic versions of the macro.
Yep, these were only WANT/NOTE comments. I think we discussed them well enough and at the end I will use whatever syntax you provide because the functionality of your library is useful to me. So no problem :) (BTW, for my usage of your library it's essential that Boost.TTI does not became a "variadics" only library especially if that is just to make the syntax look better.) --Lorenzo -- View this message in context: http://boost.2283326.n4.nabble.com/TTI-Review-tp3658414p3662959.html Sent from the Boost - Dev mailing list archive at Nabble.com.

On Tue, Jul 12, 2011 at 8:30 AM, Edward Diener <eldiener@tropicsoft.com>wrote: [...]
There is no reason to prefer replacing '<' and '>' in the syntax for the template parameters with '(' and ')' other than to complicate matters unnecessarily.
That, of course, is not entirely true; it's an alternative to replacing only commas with ")(", which makes things unnatural to read. After thinking about this last night I have decided to use a pp-array
instead of a pp-seq as the extended syntax for the non-variadic version and as an alternate syntax for the variadic version. So the syntaxes for TTI_TEMPLATE,
using 'template<class,class,class> struct xxx' and using 'template<class,int,template<**class,class> > struct yyy' are:
TTI_TEMPLATE(xxx,BOOST_PP_NIL) // (1) non-variadic only TTI_TEMPLATE(xxx) // (2) variadic only TTI_TEMPLATE(yyy,(3,(class,**int,template<class,class>))) // (3) both
[...] Isn't the above a size 4 Boost.PP Array? Or are you purposely demonstrating the ease with which the user would make mistakes with this syntax? :) - Jeff

On 7/12/2011 5:45 PM, Jeffrey Lee Hellrung, Jr. wrote:
On Tue, Jul 12, 2011 at 8:30 AM, Edward Diener<eldiener@tropicsoft.com>wrote: [...]
There is no reason to prefer replacing '<' and'>' in the syntax for the template parameters with '(' and ')' other than to complicate matters unnecessarily.
That, of course, is not entirely true; it's an alternative to replacing only commas with ")(", which makes things unnatural to read.
After thinking about this last night I have decided to use a pp-array
instead of a pp-seq as the extended syntax for the non-variadic version and as an alternate syntax for the variadic version. So the syntaxes for TTI_TEMPLATE,
using 'template<class,class,class> struct xxx' and using 'template<class,int,template<**class,class> > struct yyy' are:
TTI_TEMPLATE(xxx,BOOST_PP_NIL) // (1) non-variadic only TTI_TEMPLATE(xxx) // (2) variadic only TTI_TEMPLATE(yyy,(3,(class,**int,template<class,class>))) // (3) both
[...]
Isn't the above a size 4 Boost.PP Array? Or are you purposely demonstrating the ease with which the user would make mistakes with this syntax? :)
You copied it wrong from my reply. Are you purposely demonstrating the ease by which template parameters may be copied incorrectly <g> ? You are right that it should be: TTI_TEMPLATE(yyy,(4,(class,int,template<class,class>))) // (3) both Despite my error in counting commas ( or addding 1 to my count ), I prefer this syntax rather than inventing a different one. I realized that it is easier presenting a pp-array than a pp-seq, as long as one can simply count commas ( unlike yours truly ). Eddie

On Tue, Jul 12, 2011 at 6:51 PM, Edward Diener <eldiener@tropicsoft.com> wrote:
On 7/12/2011 5:45 PM, Jeffrey Lee Hellrung, Jr. wrote:
On Tue, Jul 12, 2011 at 8:30 AM, Edward Diener<eldiener@tropicsoft.com>wrote: [...]
TTI_TEMPLATE(yyy,(3,(class,**int,template<class,class>))) // (3) both
[...]
Isn't the above a size 4 Boost.PP Array? Or are you purposely demonstrating the ease with which the user would make mistakes with this syntax? :)
You copied it wrong from my reply. Are you purposely demonstrating the ease by which template parameters may be copied incorrectly <g> ?
Sorry... I really don't understand what this means...
You are right that it should be:
TTI_TEMPLATE(yyy,(4,(class,int,template<class,class>))) // (3) both
Despite my error in counting commas ( or addding 1 to my count ), I prefer this syntax rather than inventing a different one. I realized that it is easier presenting a pp-array than a pp-seq, as long as one can simply count commas ( unlike yours truly ).
How may commas do you count for the following case? Warning: It's a trick question ;) TTI_TEMPLATE(t, (?, (typename R, typename A0, typename A1, R (fptr)(A0, A1)))) --Lorenzo

On 7/12/2011 7:27 PM, Lorenzo Caminiti wrote:
On Tue, Jul 12, 2011 at 6:51 PM, Edward Diener<eldiener@tropicsoft.com> wrote:
On 7/12/2011 5:45 PM, Jeffrey Lee Hellrung, Jr. wrote:
On Tue, Jul 12, 2011 at 8:30 AM, Edward Diener<eldiener@tropicsoft.com>wrote: [...]
TTI_TEMPLATE(yyy,(3,(class,**int,template<class,class>))) // (3) both
[...]
Isn't the above a size 4 Boost.PP Array? Or are you purposely demonstrating the ease with which the user would make mistakes with this syntax? :)
You copied it wrong from my reply. Are you purposely demonstrating the ease by which template parameters may be copied incorrectly<g> ?
Sorry... I really don't understand what this means...
Mr. Hellrung copied the example incorrectly when he replied.
You are right that it should be:
TTI_TEMPLATE(yyy,(4,(class,int,template<class,class>))) // (3) both
Despite my error in counting commas ( or addding 1 to my count ), I prefer this syntax rather than inventing a different one. I realized that it is easier presenting a pp-array than a pp-seq, as long as one can simply count commas ( unlike yours truly ).
How may commas do you count for the following case? Warning: It's a trick question ;)
TTI_TEMPLATE(t, (?, (typename R, typename A0, typename A1, R (fptr)(A0, A1))))
I count 4 in the tuple part of the array, but since one is inside a nested tuple, ? = 4 and not 5. Are we done with school for the day <g> ? The point being, no doubt, that it is not all that easy to fill in the length for the array. I will make a point in the documentation to explain how to determine the size of the pp-lib array. It is still much easier to use the pp-lib array and transcribe the rest from the actual template parameters of the template you are searching for than either: 1) My original syntax using pp-seq. 2) Your suggested syntax replacing <> with () and other fun syntactical goodies. Let it be. It really is the easiest solution for the end-user and for me when it comes to non-variadic macros. Hopefully nearly everyone will be able to use the variadic macros syntax, either now or in the immediate future, and this syntactical issue will be completely unimportant. Paul Mensonides has said that given variadic macro support the pp-lib array is no longer useful and I concur. The only reason I am using it here is to support those very few programmers who may need it now without variadic macros. Doing really complicated preprocessor programming with non-variadic macros merely to support some syntax which may or may not be better than what I have decided is not my idea of fun or seem worthwhile to me, and I am pretty happy with my solution despite your clever example. Eddie

On Tue, Jul 12, 2011 at 6:01 PM, Edward Diener <eldiener@tropicsoft.com>wrote:
On 7/12/2011 7:27 PM, Lorenzo Caminiti wrote:
On Tue, Jul 12, 2011 at 6:51 PM, Edward Diener<eldiener@tropicsoft.com**> wrote:
On 7/12/2011 5:45 PM, Jeffrey Lee Hellrung, Jr. wrote:
On Tue, Jul 12, 2011 at 8:30 AM, Edward Diener<eldiener@tropicsoft.com**>wrote: [...]
TTI_TEMPLATE(yyy,(3,(class,****int,template<class,class>))) // (3) both
[...]
Isn't the above a size 4 Boost.PP Array? Or are you purposely demonstrating the ease with which the user would make mistakes with this syntax? :)
You copied it wrong from my reply. Are you purposely demonstrating the ease by which template parameters may be copied incorrectly<g> ?
Sorry... I really don't understand what this means...
Mr. Hellrung copied the example incorrectly when he replied.
[At the risk of being petty...] Ummm...no I didn't. I actually thought you were joking in your initial response :: cough :: http://article.gmane.org/gmane.comp.lib.boost.devel/221406 Anyways, Eddie, don't get me wrong, most of the rest of the library (as much as I've been able to get through so far, anyway) looks very sharp, the documentation is well done, and I think you've acknowledged that you will fix the more serious problems (e.g., metafunction injection to boost::tti namespace, too many macros (with the latter being fixed partially by fixing the former)), so really we're just trying to find something to pick on you for. It wouldn't be a very interesting review if we didn't, now would it? (Please take that as light heartedly as possible.) - Jeff

On 7/12/2011 9:32 PM, Jeffrey Lee Hellrung, Jr. wrote:
On Tue, Jul 12, 2011 at 6:01 PM, Edward Diener<eldiener@tropicsoft.com>wrote:
On 7/12/2011 7:27 PM, Lorenzo Caminiti wrote:
On Tue, Jul 12, 2011 at 6:51 PM, Edward Diener<eldiener@tropicsoft.com**> wrote:
On 7/12/2011 5:45 PM, Jeffrey Lee Hellrung, Jr. wrote:
On Tue, Jul 12, 2011 at 8:30 AM, Edward Diener<eldiener@tropicsoft.com**>wrote: [...]
TTI_TEMPLATE(yyy,(3,(class,****int,template<class,class>))) // (3) both
[...]
Isn't the above a size 4 Boost.PP Array? Or are you purposely demonstrating the ease with which the user would make mistakes with this syntax? :)
You copied it wrong from my reply. Are you purposely demonstrating the ease by which template parameters may be copied incorrectly<g> ?
Sorry... I really don't understand what this means...
Mr. Hellrung copied the example incorrectly when he replied.
[At the risk of being petty...] Ummm...no I didn't. I actually thought you were joking in your initial response :: cough ::
In that response above I had: "TTI_TEMPLATE(yyy,(3,(class,int,template<class,class>))) // (3) both" In your first answer above you had: "TTI_TEMPLATE(yyy,(3,(class,**int,template<class,class>))) // both (3)" And above you have: "TTI_TEMPLATE(yyy,(3,(class,****int,template<class,class>))) // both (3)" Maybe your e-mail client is adding extra 'stars' behind your back <g>.
Anyways, Eddie, don't get me wrong, most of the rest of the library (as much as I've been able to get through so far, anyway) looks very sharp, the documentation is well done, and I think you've acknowledged that you will fix the more serious problems (e.g., metafunction injection to boost::tti namespace, too many macros (with the latter being fixed partially by fixing the former)), so really we're just trying to find something to pick on you for. It wouldn't be a very interesting review if we didn't, now would it? (Please take that as light heartedly as possible.)
I understand. Can I get you to give an official review of TTI before the review period is over ? Eddie

On Tue, Jul 12, 2011 at 6:43 PM, Edward Diener <eldiener@tropicsoft.com>wrote:
On 7/12/2011 9:32 PM, Jeffrey Lee Hellrung, Jr. wrote:
On Tue, Jul 12, 2011 at 6:01 PM, Edward Diener<eldiener@tropicsoft.com**
wrote:
On 7/12/2011 7:27 PM, Lorenzo Caminiti wrote:
On Tue, Jul 12, 2011 at 6:51 PM, Edward Diener<eldiener@tropicsoft.com*
***> wrote:
On 7/12/2011 5:45 PM, Jeffrey Lee Hellrung, Jr. wrote:
On Tue, Jul 12, 2011 at 8:30 AM, Edward Diener<eldiener@tropicsoft.com****>wrote: [...]
TTI_TEMPLATE(yyy,(3,(class,******int,template<class,class>))) // (3) > both > > [...] >
Isn't the above a size 4 Boost.PP Array? Or are you purposely demonstrating the ease with which the user would make mistakes with this syntax? :)
You copied it wrong from my reply. Are you purposely demonstrating the ease by which template parameters may be copied incorrectly<g> ?
Sorry... I really don't understand what this means...
Mr. Hellrung copied the example incorrectly when he replied.
[At the risk of being petty...] Ummm...no I didn't. I actually thought you were joking in your initial response :: cough ::
In that response above I had:
"TTI_TEMPLATE(yyy,(3,(class,**int,template<class,class>))) // (3) both"
In your first answer above you had:
"TTI_TEMPLATE(yyy,(3,(class,****int,template<class,class>))) // both (3)"
And above you have:
"TTI_TEMPLATE(yyy,(3,(class,******int,template<class,class>))) // both (3)"
Maybe your e-mail client is adding extra 'stars' behind your back <g>.
I stand corrected :( No idea about the stars, I'm just using gmail.
Anyways, Eddie, don't get me wrong, most of the rest of the library (as much as I've been able to get through so far, anyway) looks very sharp, the documentation is well done, and I think you've acknowledged that you will fix the more serious problems (e.g., metafunction injection to boost::tti namespace, too many macros (with the latter being fixed partially by fixing the former)), so really we're just trying to find something to pick on you for. It wouldn't be a very interesting review if we didn't, now would it? (Please take that as light heartedly as possible.)
I understand.
Can I get you to give an official review of TTI before the review period is over ?
I started it last night; I'll finish by week's end (hopefully). I have a vested interested in this library as I have my own introspection metafunction-generating macros that I've cobbled together myself so it would be nice if something in Boost could replace those. - Jeff

On Mon, Jul 11, 2011 at 7:03 PM, Edward Diener <eldiener@tropicsoft.com> wrote:
On 7/11/2011 6:25 PM, lcaminiti wrote:
Edward Diener-3 wrote:
On 7/11/2011 5:02 PM, lcaminiti wrote:
Edward Diener-3 wrote:
On 7/11/2011 2:45 PM, Joel falcou wrote:
See :
https://github.com/MetaScale/nt2/blob/master/modules/sdk/include/nt2/sdk/det...
for the file, line 85 and after.
The point is it works without variadics
Line 87: #define NT2_PP_DETAILS_STRIP_PARENS_I(...) 1,1 Line 91: #define NT2_PP_DETAILS_TEST_ARITY_I(a,b,c,...) c Line 96: #define NT2_PP_DETAILS_MAYBE_STRIP_PARENS_2_I(...) __VA_ARGS__
Clearly it needs variadic macro support.
I have already added a REMOVE_PARENS ( the equivalent to NT2_PP_STRIP(X) in your URL above ) to a proposed addition to pp-lib which I am discussing with Paul Mensonides, based on the updated variadic macro support on which both of us worked and which is now in the Boost trunk.
My point is also that I may well be able to simplify the BOOST_TTI_TEMPLATE macros in TTI using variadic macro support techniques, as Lorenzo suggested, but I do not feel correct in dropping macro support support for compilers which do not support variadic macros although I understand there are few of them left.
I will later reply to all your comments on my review but let me quickly clarify a couple of things.
My suggestion was to have the *same* macro TTI_TEMPLATE handle *both* variadics tupletes and sequences.
I did understand it, and I am willing to do that, but of course it needs variadic macro support in the compiler. But what do you think I should do if the compiler does not support variadic macros ? The possibilities are:
I was trying to say for compilers without variaidics (detected by BOOST_NO_VARIADIC_MACROS) you can do:
TTI_TEMPLATE(trait, [tpl_signature_seq_ {class | struct}] name)
And for compilers with variadics you can do:
TTI_TEMPLATE(trait, [{tpl_signature_seq_ | tpl_signature_va_} {class | struct}] name)
Can't you? (Am I missing something?)
I do not want to stick the tpl-signature as a prefix sequence to the name. It is ugly and confusing. For some reason you like this sort of thing but I find it poor. Furthermore having to extract the template parameters from the 'name' itself may be undoable even with varaiadic macros much less with only non-variadic macros.
You have fallen in love with this sort of thing, perhaps because you have had to do something similar your 'local' library, but I will opt for a simpler and clearer way, even if it means a few extra macro names.
Fair enough. My comment #5 was just a NOTE so I actually really don't feel strongly about it (and "love" would instead be a strong feeling ;) ). If I'm the only one suggesting this syntax, you should probably ignore it.
However, as you suggested, I can do:
TTI_TEMPLATE(name,pp-seq-or-variadic-template-parameters)
Sure, my comment #6 (removing VM macros) is independent from my comment #5 (removing CHECK_PARAMS macros).
with variadic parameters support, and will look to implement a single macro on that side rather than both TTI_TEMPLATE and TTI_TEMPLATE_CHECK_PARAMS.
I'm not sure about this... wouldn't you expect the macros to be symmetric with and without variadics? In other words, if there is a CHECK_PARAMS without variadics, I would expect it to be a CHECK_PARAMS also with variadics. That is because CHECK_PARAMS does not semantically have anything to do with variadics, it is just "the macro you use when you specify the template parameters" (variadics or not). Thanks, --Lorenzo

On 7/11/2011 9:17 PM, Lorenzo Caminiti wrote:
On Mon, Jul 11, 2011 at 7:03 PM, Edward Diener<eldiener@tropicsoft.com> wrote:
On 7/11/2011 6:25 PM, lcaminiti wrote:
Edward Diener-3 wrote:
On 7/11/2011 5:02 PM, lcaminiti wrote:
Edward Diener-3 wrote:
On 7/11/2011 2:45 PM, Joel falcou wrote: > > See : > > > https://github.com/MetaScale/nt2/blob/master/modules/sdk/include/nt2/sdk/det... > > > > for the file, line 85 and after. > > The point is it works without variadics
Line 87: #define NT2_PP_DETAILS_STRIP_PARENS_I(...) 1,1 Line 91: #define NT2_PP_DETAILS_TEST_ARITY_I(a,b,c,...) c Line 96: #define NT2_PP_DETAILS_MAYBE_STRIP_PARENS_2_I(...) __VA_ARGS__
Clearly it needs variadic macro support.
I have already added a REMOVE_PARENS ( the equivalent to NT2_PP_STRIP(X) in your URL above ) to a proposed addition to pp-lib which I am discussing with Paul Mensonides, based on the updated variadic macro support on which both of us worked and which is now in the Boost trunk.
My point is also that I may well be able to simplify the BOOST_TTI_TEMPLATE macros in TTI using variadic macro support techniques, as Lorenzo suggested, but I do not feel correct in dropping macro support support for compilers which do not support variadic macros although I understand there are few of them left.
I will later reply to all your comments on my review but let me quickly clarify a couple of things.
My suggestion was to have the *same* macro TTI_TEMPLATE handle *both* variadics tupletes and sequences.
I did understand it, and I am willing to do that, but of course it needs variadic macro support in the compiler. But what do you think I should do if the compiler does not support variadic macros ? The possibilities are:
I was trying to say for compilers without variaidics (detected by BOOST_NO_VARIADIC_MACROS) you can do:
TTI_TEMPLATE(trait, [tpl_signature_seq_ {class | struct}] name)
And for compilers with variadics you can do:
TTI_TEMPLATE(trait, [{tpl_signature_seq_ | tpl_signature_va_} {class | struct}] name)
Can't you? (Am I missing something?)
I do not want to stick the tpl-signature as a prefix sequence to the name. It is ugly and confusing. For some reason you like this sort of thing but I find it poor. Furthermore having to extract the template parameters from the 'name' itself may be undoable even with varaiadic macros much less with only non-variadic macros.
You have fallen in love with this sort of thing, perhaps because you have had to do something similar your 'local' library, but I will opt for a simpler and clearer way, even if it means a few extra macro names.
Fair enough. My comment #5 was just a NOTE so I actually really don't feel strongly about it (and "love" would instead be a strong feeling ;) ). If I'm the only one suggesting this syntax, you should probably ignore it.
However, as you suggested, I can do:
TTI_TEMPLATE(name,pp-seq-or-variadic-template-parameters)
Sure, my comment #6 (removing VM macros) is independent from my comment #5 (removing CHECK_PARAMS macros).
with variadic parameters support, and will look to implement a single macro on that side rather than both TTI_TEMPLATE and TTI_TEMPLATE_CHECK_PARAMS.
I'm not sure about this... wouldn't you expect the macros to be symmetric with and without variadics? In other words, if there is a CHECK_PARAMS without variadics, I would expect it to be a CHECK_PARAMS also with variadics. That is because CHECK_PARAMS does not semantically have anything to do with variadics, it is just "the macro you use when you specify the template parameters" (variadics or not).
As my second reply explains I might be able to do a single nonvariadic macro of either: TTI_TEMPLATE(name,BOOST_PP_NIL) and TTI_TEMPLATE(name,(pp-seq)) to distinguish between the two. I will look into it. Eddie

Joel falcou-4 wrote:
On 10/07/11 22:59, Edward Diener wrote:
I will look into this. It is obviously more difficult programming with the latter than the former, but it is probably doable although with much effort. It may not be worth the effort.
What the former syntax reflects is an exact transcription of the template parameters with each comma replaced by ')(' and a starting and ending parentheses. So for the template:
'template <class,class,int,class,template <class> class InnerTemplate,class,long> struct ManyParameters { }'
the parameters are:
'(class)(class)(int)(class)(template <class> class InnerTemplate)(class)(long)'
and all I had to do as an end-user was copy the template parameters, add a '(' at the beginning, add a ')' at the end, and change every ',' to a ')('. As a programmer I take the sequence and directly convert it to the template parameters via a BOOST_PP_SEQ_ENUM.
Dunno if it helps but nt2 has a NT2_STRIP macro adapted from a amcro pasoted by Steven Watanabe that conditionnally remove parens around symbols. You can then pass parameters containing comma to the preprocessor this way :
FOO( (template<class T, class U> struct foo) )
and this way if no comma is involved
FOO( struct bar )
THe cod eis available under Boost licensing and can be incorporated w/e your need.
Hi, if the Joel proposal works for variadic anon variadic preprocessors it should retained by the library. It is much more clear than any other syntax, as follows the C++ one. Best, Vicente -- View this message in context: http://boost.2283326.n4.nabble.com/TTI-Review-tp3658414p3661446.html Sent from the Boost - Dev mailing list archive at Nabble.com.

On 7/12/2011 12:08 AM, Vicente Botet wrote:
Joel falcou-4 wrote:
On 10/07/11 22:59, Edward Diener wrote:
I will look into this. It is obviously more difficult programming with the latter than the former, but it is probably doable although with much effort. It may not be worth the effort.
What the former syntax reflects is an exact transcription of the template parameters with each comma replaced by ')(' and a starting and ending parentheses. So for the template:
'template<class,class,int,class,template<class> class InnerTemplate,class,long> struct ManyParameters { }'
the parameters are:
'(class)(class)(int)(class)(template<class> class InnerTemplate)(class)(long)'
and all I had to do as an end-user was copy the template parameters, add a '(' at the beginning, add a ')' at the end, and change every ',' to a ')('. As a programmer I take the sequence and directly convert it to the template parameters via a BOOST_PP_SEQ_ENUM.
Dunno if it helps but nt2 has a NT2_STRIP macro adapted from a amcro pasoted by Steven Watanabe that conditionnally remove parens around symbols. You can then pass parameters containing comma to the preprocessor this way :
FOO( (template<class T, class U> struct foo) )
and this way if no comma is involved
FOO( struct bar )
THe cod eis available under Boost licensing and can be incorporated w/e your need.
Hi,
if the Joel proposal works for variadic anon variadic preprocessors it should retained by the library. It is much more clear than any other syntax, as follows the C++ one.
I do not know what you mean by the "Joel proprosal". Eddie

Vicente, no, I miscliked by sayign "variadics". The macro use PP_VARIADIC stuff, I meant "no PP sequence". Edward, dont you think that compiler without variadic macro support are anyway too crippled to support the kind of metaprogramming you provide and thus will make the library not usable on these. Do we have a list of proper compiler *without* such a support ?

On 7/12/2011 10:51 AM, Joel falcou wrote:
Vicente, no, I miscliked by sayign "variadics". The macro use PP_VARIADIC stuff, I meant "no PP sequence".
Edward, dont you think that compiler without variadic macro support are anyway too crippled to support the kind of metaprogramming you provide and thus will make the library not usable on these.
I honestly do not know. Clearly it is easier for me to just ignore compilers which do not support variadic macros when I program TTI_HAS_TEMPLATE_CHECK_PARAMS or attempt to combine TTI_HAS_TEMPLATE and TTI__HAS_TEMPLATE_CHECK_PARAMS into a single macro. But I did feel I should not do this and support compilers which may not have variadic macro support.
Do we have a list of proper compiler *without* such a support ?
It is not so much compilers without variadic support as compiler switches which turn on variadic macro support. I had a discussion with Paul Mensonides when we worked on pp-lib to provide variadic macro support about the compilers we would support. Originally it was programmed to follow the support in Boost config for variadic macros which I spearheaded. But Paul insisted on a stricter definition of variadic macro support so that warning messages do not appear from some compilers and the compilers either support c99 or c++0x for variadic macros. I am perfectly willing to tell an end-user that they can not use the equivalent of TTI_HAS_TEMPLATE_CHECK_PARAMS functionality if their compiler can not handle variadic macro syntax if that is how the vast majority of others feel about it.

Edward Diener wrote:
On 7/10/2011 7:59 PM, Lorenzo Caminiti wrote:
Review of Boost.TTI 2011-07-10 (Lorenzo Caminiti)
10. [NOTE] I think "member variable" is a more accepted name that "member data"-- isn't it? If so, I'd rename MEMBER_DATA to MEMBER_VARIABLE.
I can understand your preference. I will consider it.
They are called data members, not member variables, in C++. Names like "member variable" come from other languages. I don't use "member data" generally, but to me it describes data members collectively, not singularly. I recognize the desire to keep the prefixes alike, but I'd rather see "HAS_DATA_MEMBER" to be consistent with Standard terminology. _____ Rob Stewart robert.stewart@sig.com Software Engineer using std::disclaimer; Dev Tools & Components Susquehanna International Group, LLP http://www.sig.com ________________________________ IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

On 7/11/2011 10:56 AM, Stewart, Robert wrote:
Edward Diener wrote:
On 7/10/2011 7:59 PM, Lorenzo Caminiti wrote:
Review of Boost.TTI 2011-07-10 (Lorenzo Caminiti)
10. [NOTE] I think "member variable" is a more accepted name that "member data"-- isn't it? If so, I'd rename MEMBER_DATA to MEMBER_VARIABLE.
I can understand your preference. I will consider it.
They are called data members, not member variables, in C++. Names like "member variable" come from other languages.
I don't use "member data" generally, but to me it describes data members collectively, not singularly.
I recognize the desire to keep the prefixes alike, but I'd rather see "HAS_DATA_MEMBER" to be consistent with Standard terminology.
I agree with your remark about the normal terminology. I could have used HAS_DATA_MEMBER and HAS_MEMBER_FUNCTION but I wanted to align the names around a common beginning. That is why I chose HAS_MEMBER_DATA and HAS_MEMBER_FUNCTION. Similarly HAS_STATIC_MEMBER_DATA and HAS_STATIC_MEMBER_FUNCTION. Sometimes such mnemonic similarities ( having the same common beginnings ) is more important than other factors. I know that this may start some long discussion about names in TTI, but here is a general suggestion to all programmers who are ever upset about names in a library, and does not just refer to TTI: if you do not like a name, just create an object-like macro for your own use which takes some name and transforms it to some other name which you like better. Lorenzo might write the macro: #define BOOST_TTI_HAS_MEMBER_VARIABLE BOOST_TTI_HAS_MEMBER_DATA and you might write the macro: #define BOOST_TTI_HAS_DATA_MEMBER BOOST_TTI_HAS_MEMBER_DATA This is guaranteed to work without problems all the time AFAIK to transform one name to another. Eddie

Edward Diener-3 wrote:
On 7/11/2011 10:56 AM, Stewart, Robert wrote:
Edward Diener wrote:
On 7/10/2011 7:59 PM, Lorenzo Caminiti wrote:
Review of Boost.TTI 2011-07-10 (Lorenzo Caminiti)
10. [NOTE] I think "member variable" is a more accepted name that "member data"-- isn't it? If so, I'd rename MEMBER_DATA to MEMBER_VARIABLE.
I can understand your preference. I will consider it.
They are called data members, not member variables, in C++. Names like "member variable" come from other languages.
I don't use "member data" generally, but to me it describes data members collectively, not singularly.
I recognize the desire to keep the prefixes alike, but I'd rather see "HAS_DATA_MEMBER" to be consistent with Standard terminology.
I agree with your remark about the normal terminology. I could have used HAS_DATA_MEMBER and HAS_MEMBER_FUNCTION but I wanted to align the names around a common beginning. That is why I chose HAS_MEMBER_DATA and HAS_MEMBER_FUNCTION. Similarly HAS_STATIC_MEMBER_DATA and HAS_STATIC_MEMBER_FUNCTION. Sometimes such mnemonic similarities ( having the same common beginnings ) is more important than other factors.
I know that this may start some long discussion about names in TTI, but here is a general suggestion to all programmers who are ever upset about names in a library, and does not just refer to TTI: if you do not like a name, just create an object-like macro for your own use which takes some name and transforms it to some other name which you like better.
Lorenzo might write the macro:
#define BOOST_TTI_HAS_MEMBER_VARIABLE BOOST_TTI_HAS_MEMBER_DATA
and you might write the macro:
#define BOOST_TTI_HAS_DATA_MEMBER BOOST_TTI_HAS_MEMBER_DATA
This is guaranteed to work without problems all the time AFAIK to transform one name to another.
My comment #10 started by asking if member variable is the common name. As it has been pointed out, it is not. From Stroustrup C.12 (page 853) "data member" is the common name so I think MEMBER_DATA is the appropriate name and the one I would like to use (this discussion is about the name that the C++ standard uses, not the name I like). BTW, still from Stroustrup C.12 (page 853) there exist a composite form from data members, not just member functions: typedef void (C::* member_func_type)(int); typedef const char* C::* member_var_type; So back to my comment #11, I would like to see: TTI_MEMBER_DATA(has_number, number) has_number<int T::*> // [1] Instead of: has_number<T, int> [2] Again, I would only provide the composite form for checking member functions (my comment #9) and for consistency I would only provide [1] (not [2]) for data members (my comment #11). Thanks, --Lorenzo -- View this message in context: http://boost.2283326.n4.nabble.com/TTI-Review-tp3658414p3660881.html Sent from the Boost - Dev mailing list archive at Nabble.com.

On 7/11/2011 5:17 PM, lcaminiti wrote:
Edward Diener-3 wrote:
On 7/11/2011 10:56 AM, Stewart, Robert wrote:
Edward Diener wrote:
On 7/10/2011 7:59 PM, Lorenzo Caminiti wrote:
Review of Boost.TTI 2011-07-10 (Lorenzo Caminiti)
10. [NOTE] I think "member variable" is a more accepted name that "member data"-- isn't it? If so, I'd rename MEMBER_DATA to MEMBER_VARIABLE.
I can understand your preference. I will consider it.
They are called data members, not member variables, in C++. Names like "member variable" come from other languages.
I don't use "member data" generally, but to me it describes data members collectively, not singularly.
I recognize the desire to keep the prefixes alike, but I'd rather see "HAS_DATA_MEMBER" to be consistent with Standard terminology.
I agree with your remark about the normal terminology. I could have used HAS_DATA_MEMBER and HAS_MEMBER_FUNCTION but I wanted to align the names around a common beginning. That is why I chose HAS_MEMBER_DATA and HAS_MEMBER_FUNCTION. Similarly HAS_STATIC_MEMBER_DATA and HAS_STATIC_MEMBER_FUNCTION. Sometimes such mnemonic similarities ( having the same common beginnings ) is more important than other factors.
I know that this may start some long discussion about names in TTI, but here is a general suggestion to all programmers who are ever upset about names in a library, and does not just refer to TTI: if you do not like a name, just create an object-like macro for your own use which takes some name and transforms it to some other name which you like better.
Lorenzo might write the macro:
#define BOOST_TTI_HAS_MEMBER_VARIABLE BOOST_TTI_HAS_MEMBER_DATA
and you might write the macro:
#define BOOST_TTI_HAS_DATA_MEMBER BOOST_TTI_HAS_MEMBER_DATA
This is guaranteed to work without problems all the time AFAIK to transform one name to another.
My comment #10 started by asking if member variable is the common name. As it has been pointed out, it is not. From Stroustrup C.12 (page 853) "data member" is the common name so I think MEMBER_DATA is the appropriate name and the one I would like to use (this discussion is about the name that the C++ standard uses, not the name I like).
BTW, still from Stroustrup C.12 (page 853) there exist a composite form from data members, not just member functions:
typedef void (C::* member_func_type)(int); typedef const char* C::* member_var_type;
So back to my comment #11, I would like to see:
TTI_MEMBER_DATA(has_number, number)
has_number<int T::*> // [1]
Instead of:
has_number<T, int> [2]
Your editor messed things up, so I assume you meant: 'has_number<T, int>; [2]' just above. The problem is that your preferred syntax [1] does not allow the result from MEMBER_TYPE to be passed separately as a single type, whereas [2] does allow it. Please try reading my explanation in the documentation again about MEMBER_TYPE, why it is so useful, and and therefore why syntax which allows individual types to be passed should always be preferred. If, after looking at that again in the doc, you do not understand what I am getting at, i will be glad to explain it in this thread. I admit that my explanation for MEMBER_TYPE may not be the clearest and easiest to understand and in the revised doc I will be explaining it in a simpler and hopefully easier to under manner.
Again, I would only provide the composite form for checking member functions (my comment #9) and for consistency I would only provide [1] (not [2]) for data members (my comment #11).
Again if you understand MEMBER_TYPE and for what it is used, you will understand the weakness of purely composite forms in TTI. Eddie

Edward Diener-3 wrote:
On 7/11/2011 5:17 PM, lcaminiti wrote:
Edward Diener-3 wrote:
On 7/11/2011 10:56 AM, Stewart, Robert wrote:
Edward Diener wrote:
On 7/10/2011 7:59 PM, Lorenzo Caminiti wrote:
Review of Boost.TTI 2011-07-10 (Lorenzo Caminiti)
10. [NOTE] I think "member variable" is a more accepted name that "member data"-- isn't it? If so, I'd rename MEMBER_DATA to MEMBER_VARIABLE.
I can understand your preference. I will consider it.
They are called data members, not member variables, in C++. Names like "member variable" come from other languages.
I don't use "member data" generally, but to me it describes data members collectively, not singularly.
I recognize the desire to keep the prefixes alike, but I'd rather see "HAS_DATA_MEMBER" to be consistent with Standard terminology.
I agree with your remark about the normal terminology. I could have used HAS_DATA_MEMBER and HAS_MEMBER_FUNCTION but I wanted to align the names around a common beginning. That is why I chose HAS_MEMBER_DATA and HAS_MEMBER_FUNCTION. Similarly HAS_STATIC_MEMBER_DATA and HAS_STATIC_MEMBER_FUNCTION. Sometimes such mnemonic similarities ( having the same common beginnings ) is more important than other factors.
I know that this may start some long discussion about names in TTI, but here is a general suggestion to all programmers who are ever upset about names in a library, and does not just refer to TTI: if you do not like a name, just create an object-like macro for your own use which takes some name and transforms it to some other name which you like better.
Lorenzo might write the macro:
#define BOOST_TTI_HAS_MEMBER_VARIABLE BOOST_TTI_HAS_MEMBER_DATA
and you might write the macro:
#define BOOST_TTI_HAS_DATA_MEMBER BOOST_TTI_HAS_MEMBER_DATA
This is guaranteed to work without problems all the time AFAIK to transform one name to another.
My comment #10 started by asking if member variable is the common name. As it has been pointed out, it is not. From Stroustrup C.12 (page 853) "data member" is the common name so I think MEMBER_DATA is the appropriate name and the one I would like to use (this discussion is about the name that the C++ standard uses, not the name I like).
BTW, still from Stroustrup C.12 (page 853) there exist a composite form from data members, not just member functions:
typedef void (C::* member_func_type)(int); typedef const char* C::* member_var_type;
So back to my comment #11, I would like to see:
TTI_MEMBER_DATA(has_number, number)
has_number<int T::*> // [1]
Instead of:
has_number<T, int> [2]
Your editor messed things up, so I assume you meant:
'has_number<T, int>; [2]' just above.
The problem is that your preferred syntax [1] does not allow the result from MEMBER_TYPE to be passed separately as a single type, whereas [2] does allow it.
Please try reading my explanation in the documentation again about MEMBER_TYPE, why it is so useful, and and therefore why syntax which allows individual types to be passed should always be preferred. If, after looking at that again in the doc, you do not understand what I am getting at, i will be glad to explain it in this thread. I admit that my explanation for MEMBER_TYPE may not be the clearest and easiest to understand and in the revised doc I will be explaining it in a simpler and hopefully easier to under manner.
Again, I would only provide the composite form for checking member functions (my comment #9) and for consistency I would only provide [1] (not [2]) for data members (my comment #11).
Again if you understand MEMBER_TYPE and for what it is used, you will understand the weakness of purely composite forms in TTI.
OK, I see. I remember you mentioned about MEMBER_TYPE in replying to my review and that is why you wanted to keep the non-composite member function macros. I did read the MEMBER_TYPE docs. I think I understand the issue but I need to think about it more. I will let you know. --Lorenzo -- View this message in context: http://boost.2283326.n4.nabble.com/TTI-Review-tp3658414p3660989.html Sent from the Boost - Dev mailing list archive at Nabble.com.

Stewart, Robert wrote:
Edward Diener wrote:
On 7/10/2011 7:59 PM, Lorenzo Caminiti wrote:
Review of Boost.TTI 2011-07-10 (Lorenzo Caminiti)
10. [NOTE] I think "member variable" is a more accepted name that "member data"-- isn't it? If so, I'd rename MEMBER_DATA to MEMBER_VARIABLE.
I can understand your preference. I will consider it.
They are called data members, not member variables, in C++. Names like "member variable" come from other languages.
I don't use "member data" generally, but to me it describes data members collectively, not singularly.
I recognize the desire to keep the prefixes alike, but I'd rather see "HAS_DATA_MEMBER" to be consistent with Standard terminology.
+1. Following the standard terminology will avoid confusion. Best, Vicente -- View this message in context: http://boost.2283326.n4.nabble.com/TTI-Review-tp3658414p3661449.html Sent from the Boost - Dev mailing list archive at Nabble.com.

On Sun, Jul 10, 2011 at 11:59 PM, Edward Diener <eldiener@tropicsoft.com> wrote:
On 7/10/2011 7:59 PM, Lorenzo Caminiti wrote:
Review of Boost.TTI 2011-07-10 (Lorenzo Caminiti) =================================================
Do you think the library should be accepted as a Boost library? ---------------------------------------------------------------
Yes, in my opinion Boost.TTI should be accepted as a Boost library.
Appreciated !
Thank you for programming libraries that make my programming easier (like TTI and VMD). As I said, I am going to reply to all your comments here one by one.
Key points are:
1) I would essentially found this library useful as is.
2) The library should not expand its macros into the boost::tti namespace (I give a few reasons and suggest alternatives below).
3) The library uses too many macros to provide essentially the same functionality (with minor variations). This is confusing and the library macro API should be simplified (I suggest a possible simplification below).
I will answer each of your points below rather than generally answering 2) or 3) above.
My comments are all numbered and marked as follow: [MUST] If these comments are not addressed, I would no longer recommend to add this library into Boost. [WANT] I would like to see these comments addressed but I would still recommend to add this library into Boost even if these comments are not addressed. [NOTE] I do not feel strongly about these comments and the authors can ignore these comments if they wish to do so.
What is your evaluation of the design? --------------------------------------
1. [MUST] The library provides too many macros (with very similar functionality) which make the interface difficult to grasp. The authors should take some time to try to redesign and simply the library interface ideally reducing the number of macros.
I will give my reasons for each of the macros in answer to your suggestions below, but I completely agree that if the number of macros could be simplified and still offer the same basic functionality it should be done.
[WANT] I would reduce the macro API to the following 5 macros (no more, as I explain in the rest of the comments below):
HAS_TYPE(has_mytype, mytype) HAS_TEMPLATE(has_mytpl, [template(...) {class|struct}] mytpl)
I can look into combining the various template macros if it can be done. Currently there are three variations, disregarding the complex form of each macro. The variations are:
BOOST_TTI_HAS_TEMPLATE(name) BOOST_TTI_HAS_TEMPLATE_CHECK_PARAMS(name,pp-seq-of params) BOOST_TTI_VM_HAS_TEMPLATE_CHECK_PARAMS(name,variadic-sequence-of-params)
You would like to see a single macro, called BOOST_TTI_HAS_TEMPLATE, which could alternately take a pp-seq-of params or a variadic-sequence-of-params. I agree that would be wonderful if it could be done.
To do this the compiler must support variadic macros AFAICS. What if the
No, if the compiler does not support variadics then the macro will only accept the pp-sequence. If the compiler supports variadics then the macro will accepts both the pp-sequence and the variadic pp-tuple. It should be possible to program this using pp techniques similar to the ones I have used to program BOOST_LOCAL_FUNCTION_PARAMS (see http://svn.boost.org/svn/boost/sandbox/local/boost/local/function.hpp). That clarified, I think we discussed this point enough in the other replies to this email thread. At the end I will use any API you decide to provide so case closed :)
end-user's compiler does not do so ? Even if the end-user's compiler supports variadic macros, how do I tell the difference between a pp-seq of params and a variadic-sequence of params ?
So here are my thoughts. If I supported the single macro for compilers which support variadic macros, I still need to support the two non-variadic macro versions for compilers which do not support variadic macros.
For the variadic macro version I can find out that is the variadic-sequence-of-params if it has more than one variadic parameter after the name. If it only has one variadic parameter after the name I can check if the parameter starts with a set of parens and, if it does, it is the pp-seq of params, else it is the variadic-sequence of params. I think this is doable. But I still can not see my way around dropping support completely for the non-variadic versions of this macro.
HAS_MEMBER_VARIABLE(has_myvar, [static] myvar) HAS_MEMBER_FUNCTION(has_myfunc, [static] myfunc)
I can easily combine BOOST_TTI_HAS_MEMBER_DATA and BOOST_TTI_HAS_STATIC_MEMBER_FUNCTION into HAS_MEMBER_VARIABLE, which covers either case, and BOOST_TTI_HAS_MEMBER_FUNCTION and BOOST_TTI_HAS_STATIC_MEMBER_FUNCTION into a HAS_MEMBER_FUNCTION, which cover either case. But then the end-user will lose the ability to distinguish between a 'member data/static member data' or 'member function/static member function'. Do you really think that is the correct thing to do just because you think there are too many macros ? I do not.
OTOH I do not mind adding the combined member data and member function macros as you suggested, while keeping what already exists, but then that adds more macros ( which does not bother me a bit ), which you do not like.
See below for my comments about the composite type functions.
MEMBER_TYPE(trait, name)
2. [MUST] Expanding the metafunctions within the boost::tti namespace presents a number of serious issues: a) If multiple part of the program (possibly independent libraries) use the TTI library to introspect the same name, the metafunction names will clash. b) The library macros can only be used at namespace scope. However, it should be possible to use the macros also at class scope so to define the introspection metafunctions as inner classes, etc (this is critical for example in my application for Boost.TTI where I use it to implement Boost.Contract and all Boost.Contract macros expand at class scope).
BTW, the docs should indicate within which scope the macros can be used. I think the macros should be used within namespace and class/struct scope. Unfortunately, I don't think there is a way to use the macros within local scope (e.g., within a function) because local classes cannot be templates. This should be documented.
The authors should address these issues.
I totally agree with your criticism here and I will remove the generated macros from any namespace. Others have also mentioned the same thing and I immediately realized they were right when I read their reasoning.
[WANT] To address these issues, I would suggest to simply define the metafunctions within the enclosing scope. It will be the user's responsibility to use the macros within the correct scope (namespace, class, etc). For example:
template< class T> struct OurTemplateClass { BOOST_TTI_HAS_TYPE(has_mytype, _mytype) // also at class scope
void f() { std::cout<< has_mytype<T>::value<< std::endl; } };
This should also allow to remove all the GEN/GEN_BASE macros.
I can remove the GEN_BASE set but I would still keep the GEN set ( which would be the same as the current GEN_BASE set ) in order to provide an easy way to generate the metafunction name from the appropriate macro, without the end-user having to manually remember the algorithm by which I generate the metafunction name.
See below for my comments about generating the metafunction name.
3. [MUST] The library macros prefix the specified name with _ but this can create a symbol with double underscores __ which is reserved by C++ (e.g., HAS_TYPE(_my_type) creates a metafunction named boost::tti::has_type__my_type which is a reserved symbol). The authors should address this issue.
You have made a good point and I can simply remove the preceding '_' when generating the final metafunction name.
But then HAS_TYPE(mytype) generates the unreadable name has_typemytype :( Unfortunately, as a user of your library I won't think this is a good solution...
[WANT] To address this issue (and also to reduce the number of macros eliminating the need for separate TRAIT macros), I would suggest to always ask the user to specify both the trait and the introspected name (not just the introspected name) and then use the trait to name the metafunction (as always, it is the user's responsibility to not use reserved names). For example:
HAS_TYPE(has_mytype, _mytype) // generates metafunc has_my_type
This should also allow to remove all the TRAIT macros.
You want to remove functionality for automatically generating a macro metafunction name just because you feel there are too many macros. I believe
No, it's for two reasons (1) the generated name can contain __ and (2) there are too many macros (not just (2)). As I said, if you address (1) by removing the _ prefix then the names will be unreadable: HAS_TYPE(mytype) // generates has_typemytype I think the name has_typemytype is unreadable. I will then always use the TRAIT macros to generate more readable names like has_type_mytype and making the automatic name generation functionality useless. However, if you can fully address (1) then (2) might not be a strong enough reason to remove the automatic name generation but how can you really address (1) in general? Just to shared some ideas, I tough about the possibility to generate a name like has_type::mytype. For example, using an enclosing struct: struct has_type { template< typename T > class mytype { ... }; // metafunc from your macro }; But then you cannot expand two macros HAS_TYPE(mytype) and HAS_TYPE(yourtype) within the same context because the enclosing struct name has_type will clash so I concluded this a very bad idea. Also you can't use a namespace has_type because of all the namespace issues we already discussed... too bad because if there was a way to automatically generate a name like has_type::mytype I think the automatic name generation functionality would be cool.
that the automatic generation of the metafunction name is welcomed by metaprogrammers. The MPL macros BOOST_MPL_HAS_XXX_TEMPLATE_DEF/BOOST_MPL_HAS_XXX_TEMPLATE_NAMED_DEF and BOOST_MPL_HAS_XXX_TRAIT_DEF/BOOST_MPL_HAS_XXX_TRAIT_NAMED_DEF follow the scheme I have chosen.
4. [WANT] I really think that mixing () and<> parenthesis is confusing:
HAS_TEMPLATE_CHECK_PARAMS(MoreParameters, (class) (class) (int) (short) (class) (template<class)(int> class InnerTemplate) // confusing :( (class) )
IMO, this would be more readable as the following:
HAS_TEMPLATE_CHECK_PARAMS(MoreParameters, (class) (class) (int) (short) (class) (template( (class) (int) ) class InnerTemplate) // ok :) (class) )
I will look into this. It is obviously more difficult programming with the latter than the former, but it is probably doable although with much effort. It may not be worth the effort.
What the former syntax reflects is an exact transcription of the template parameters with each comma replaced by ')(' and a starting and ending parentheses. So for the template:
'template <class,class,int,class,template <class> class InnerTemplate,class,long> struct ManyParameters { }'
the parameters are:
'(class)(class)(int)(class)(template <class> class InnerTemplate)(class)(long)'
and all I had to do as an end-user was copy the template parameters, add a '(' at the beginning, add a ')' at the end, and change every ',' to a ')('. As a programmer I take the sequence and directly convert it to the template parameters via a BOOST_PP_SEQ_ENUM.
I think we discussed this well enough in previous replies to this email thread. Please try to think first of the syntax that your library users (your customers) will find most useful and don't think about how complex it will be to pp-program within your library. Again, at the end I will use any syntax you decide to provide.
5. [NOTE] There is no real need to use another macro ..._CHECK_PARAMS because HAS_TEMPLATE can be reused. This would reduce the number of macros. For example, with template parameters:
HAS_TEMPLATE( template( // gives the parameters (optional) (class) (class) (int) (short) (class) (template( (class) (int) ) class InnerTemplate) (class) ) struct MoreParameters // struct or class can be used here )
And the same macro without template parameters:
HAS_TEMPLATE(MoreParameters)
See above for my answer to this.
6. [NOTE] The same macros can accept both pp-sequences and variadic pp-tuples (when variadic macros are supported). This eliminates the VM macros reducing the number of different macros in the library API. For example:
HAS_TEMPLATE( template( class, class, int, short, class, template( class, int ) class InnerTemplate, // variadic commas class ) struct MoreParameters )
I know this uses template( class, int ) instead of template< class, int> but this way the syntaxes with and without variadics are unified and consistent (and more readable IMO). Alternatively, you can probably program the macro with variadic to be:
HAS_TEMPLATE( template< // template< > here class, class, int, short, class, template< class, int> class InnerTemplate, // template< > here class > struct MoreParameters )
But still keep the following syntax without variadics:
HAS_TEMPLATE( template( // template( ) here (class) (class) (int) (short) (class) (template( (class) (int) ) class InnerTemplate) // template( ) here (class) ) struct MoreParameters )
See above for my answer to this.
7. [WANT] Can the authors explain why the inner template parameter name InnerTemplate is needed while all other template parameter names are not needed? Is it really needed? Why I cannot do:
HAS_TEMPLATE( template( class, class, int, short, class, template( class, int ) class, // no name InnerTemplate class ) struct MoreParameters )
It should not be needed. Please try without it. If it does not work I will look and see why and attempt to correct it.
I didn't have time to try. However, can you please verify this and remove the InnerTemplate parameter name from the docs? (Or put a note in the docs that say why this parameter name is needed.) I got confused because the docs name this one parameter but not the other parameters...
8. [NOTE] There is no need to use a different set of macros for static because the keyword static can be used to have the pp detect this case. This will reduce the number of different macros. For example:
HAS_STATIC_MEMBER_FUNCTION(has_static_f, f)
Can be replaced by:
HAS_MEMBER_FUNCTION(has_static_f, static f)
See above for my previous discussion on dropping the distinction between member functions and static member functions.
We discussed this well enough in other replies to this email thread. I totally respect your decision that [1] is more clear than [2]: HAS_STATIC_MEMBER_FUNCTION(func) // [1] HAS_MEMBER_FUNCTION(static func) // [2] However, I would like to offer the reflection that [2] is a more flexible API than [1]. Say your library is expanded to detect public, protected, and private and you can do that for both static and non-static member functions. Then you will have to provide lots of macros for all these combinations: HAS_MEMBER_FUNCTION HAS_PUBLIC_MEMBER_FUNCTION HAS_PROTECTED_MEMBER_FUNCTION HAS_PRIVATE_MEMBER_FUNCTION HAS_STATIC_MEMBER_FUNCTION HAS_STATIC_PUBLIC_MEMBER_FUNCTION HAS_STATIC_PROTECTED_MEMBER_FUNCTION HAS_STATIC_PRIVATE_MEMBER_FUNCTION Now say you can also detect virtual public, protected, or private member functions, you have to add another 4 macros for that too... Instead the other syntax will only and always use 1 macro: HAS_MEMBER_FUNCTION( [public | protected | private] [static | virtual] func ) So the API [2] will never blowout if more traits can be introspected while [1] will blowout fast. That said, this is not a concern for your library right now because you can only introspect the one static trait.
9. [WANT] Why can't we always use the composite function syntax R (C::*)(A0, A1, ...)? This is similar to the preferred notation for Boost.Function so if possible it should be used instead of the other notation.
As I understand it, some compilers have troubles supporting the composite syntax. However, these compilers might not be able to support the TTI library all together. Unless there is evidence of compilers that can support TTI but not the composite function syntax, I think only the composite function notation should be provided.
This should also allow to remove all the COMP macros.
The reason for having both a composite syntax, which you like, and the non-composite syntax of individual types is:
1) The composite type syntax can be used when one has to pass a calling convention, or possible some compiler-specified function-like syntax, which the function_types 'tag' type does not support. I think this is absolutely necessary to have.
2) The individual type syntax is there so that MEMBER_TYPE can be used to pass a nested type which does not have to exist without causing a compiler error. I also thin this is absolutely necessary to have.
Please read the section called 'Nested Types' in the documentation to understand why MEMBER_TYPE is used. The ability to pass a nested type in the form of a MEMBER_TYPE as a function parameter is very important piece of functionality. Being able to do this for a function parameter type or for the function return type is something I do not want to eliminate.
Thank you for explaining this. I am still thinking about it... Could you please reply with an example of a MEMBER_TYPE can is used with the individual type syntax but fails if passed to the composite syntax? That will help me a lot in fully understanding this issue.
10. [NOTE] I think "member variable" is a more accepted name that "member data"-- isn't it? If so, I'd rename MEMBER_DATA to MEMBER_VARIABLE.
I can understand your preference. I will consider it.
11. [WANT] Is it possible to have some sort of composite syntax for member variables?
There is no reason to have a composite syntax for member variables. A member variable is a single type.
As I said in a previous reply (1) the C++ standard name is data member (so HAS_MEMBER_DATA or HAS_DATA_MEMBER are good names as far as I am concerned) and (2) there exist a composite data member syntax: struct c { int x; }; int c::* // type of pointer to int data member of c So: HAS_MEMBER_DATA(x) // [1] has_x<c, int> // 2 tparams HAS_COMP_MEMBER_DATA(x) // [2] has_comp_x<int c::*> // 1 (composite) tparam That said if you think there is no reason to support the composite data member syntax [2], that's fine. I'd add a note to the docs explaining why the composite syntax is supported for member functions but not for data members.
I remember reading something about this for overloading the operator ->* to access member variables (as well as calling member functions) but I can't double check right now... can the authors look into this? For example:
HAS_MEMBER_VARIABLE(has_number, number)
has_number<T::short> // composite form for member variable?
If there exists a composite form for member variables, I would like the generated metafunctions to use it instead of the plain form (so to be consistent with the MEMBER_FUNCTION macros-- see comment above).
12. [WANT] Are the metafunction MTFC macros really needed? The docs say they reduce compile-time (compared to using MPL placeholders) but no evidence is shown to support that...
Extra macros complicate the library API so if they are provided for reducing compile-time there should be some benchmarking showing their benefits. If not, these macros should be removed.
[NOTE] If these macros are shown to be beneficial, I'd rename them with a METAFUNC postfix because I find it more readable. For example:
HAS_TYPE_METAFUNC HAS_MEMBER_FUNCTION_METAFUNC
I supplied them merely as a convenience. In an early mailing list message about the TTI library from Dave Abrahams, before this review, he suggested that passing metafunctions as data as a metafunction class would generally be faster than passing them via placeholder expressions. I do not mind eliminating them if it seen as overkill.
If there is evidence (compile-time data and possibly some explanation) of that MTFC have faster compile-time, leave the macros. However, I thinks you either (1) measure the compile-times add the evidence in the docs or (2) you remove the MTFC macros.
13. [WANT] Are the nullary metafunctions really needed?
Functionally, no, which the documentation explicitly explains. Syntactically I feel they are much easier to use once they are understood.
The docs say they simplify the syntax but no side-by-side example comparing the syntax with and without the nullary type metafunctiosn is provided...
Unless their benefit is clearly shown, the nullary metafunctions should be remove to simplify the library API.
I will add side by side examples showing the simpler syntax of using the nullary metafunctions. I do show the different syntaxes for similar situations in the doc, but not side by side.
Can you please reply to this email with a short example that compares the two syntaxes so we can all take a look at it?
Why not just ignore them if you do not like their syntax ? After all tghey
Because as a new user of your library I think "are they important?", "shall I learn them?", "do I need/want their simpler syntax?". So if they really offer a benefit (even just syntactical), they should be there, just illustrate their benefit better.
are just a set of metafunctions, which no one has to learn to use if they do not want to do so. They do not interfere with anything else in the library and they allow specifying nested types in a syntactically easier way.
14. [NOTE] I'd fully spell the header file names to improve readability and be consistent with the macro names (which are correctly fully spelled). For example, "member_function.hpp" instead of "mem_fun.hpp".
I can do that, and probably will. You have a good point.
15. [NOTE] I'd rather use an actual name for the library instead of the cryptic acronym TTI (but I personally don't like the widely used MPL neither so maybe it's just me). Maybe "intro" (for introspection), or "mirror" (look at yourself), or "soul" (look into your soul), or "psycho" (look into your person) ;) would be better names...
Where would you like to see the longer name ? I certainly do not mind calling the library Type Traits Introspection but that is quite a mouthful. Like MPL ( for Metaprogramming Library ), TTI is easier to remember and refer to.
What is your evaluation of the implementation? ----------------------------------------------
16. I did not look at the implementation.
What is your evaluation of the documentation? ---------------------------------------------
17. [WANT] I'd add a "Motivating Example" in the Introduction section to very briefly illustrate the library functionality (probably right after the bullet list on the library functionalities). I had to go all the way into the Nested Types section to start seeing some code... (I was motivated just because I knew what the library does and I've used MPL_XXX macros with SFINAE before).
I totally agree with you. I intend to revamp the introductory material to make it simpler and easier to understand what the library can do, and present some basic motivating examples.
18. [NOTE] I don't think you need a space before "?" in English (see "Why the TTI Library ?", etc).
You are right. I will change it. It is just my style but unnecessary.
19. [WANT] Typo in "depending on how many parameters are bring passed".
Corrected ! Thanks !
What is your evaluation of the potential usefulness of the library? -------------------------------------------------------------------
20. [NOTE] The library is very useful as is. For example, I use a similar introspection technique in Boost.Contract as part of a mechanism to check if a base class has a virtual function that is being overridden so to automatically subcontract from such a base class function.
21. [WANT] I think the docs should add an annex with a complete list of all traits that would ideally be introspected even if they cannot actually be introspected. For example, a table could list all traits that would be good to introspect and then for each trait say "introspected by this library", or "cannot be introspected in C++ because...", etc. For example, Boost.Contract could use the ability to check if a function is public, protected, or private to simplify its macro syntax (because only public functions shall check class invariants).
Possible traits for introspection I can think of are: is public, is protected, is private, is template, has these template parameters, is explicit, is inline, is extern, is static, is virtual, is const member, is volatile member, has these exception specifications (throw), any more?
I think your possible list is too arbitrary. Most anything can be added here.
No, my list is not arbitrary but it tries to include _all_ the traits in a function (free, member, constructor, and destruct) declaration: func_signature_: // for free functions, member functions, constructors, and destructors [public | protected | private] [[export] [template< template_param, ... >] [explicit] [inline] [extern] [static] [virtual] [result_type_] func_name_ ( func_params_ ) [const] [volatile] [throw( [expections_] )] Also: 1) How about classes? For example, a metafunction to introspect "is B a protected base of class C?" 2) How about namespaces? For example, a metafunction to introspect "is f an free function in namespace n?" It is true that most anything can be added here. However, the traits supported by TTI are actually arbitrary. Why there is a matafunction for "is f a static member of class C?" but not for "is f a virtual member of class C?". From a library user prospective, I might be interested in the static trait as much or as well as in the virtual trait. However, TTI now introspects the static trait but not the virtual trait and that seems arbitrary for the user. If other traits cannot be introspected (like virtual, public, etc), that is fine but you should document somewhere that TTI does not introspect them not because we "forgot" these other traits but because it is not possible to introspect them in C++. Also this annex should serve as the "total" reference for C++ introspection. If I want to know if a public member function can be introspected in C++, I should be able to look at your library and either find the API that introspects the public trait or find that such a trait cannot be introspected. I think you need to address all the other traits (maybe just saying they cannot be introspected) otherwise you library is not a general introspection library but it is an introspection library only for the 4 traits it can introspect.
22. [WANT] I'd add an annex to the docs to compare this library with other libraries (e.g., the "mirror" library?) that exist out there for introspection (i.e., some sort of literature review).
if there were an existing Boost library I might do it.
Why would you compare Boost.TTI only with other Boost libraries? You should do a literature search on C++ introspection in general and compare Boost.TTI with *all* known C++ introspection library even/especially if they are not in Boost.
I would also comment on possible C++ standard extensions or compiler specific support for introspection.
Which C++ standard ( 2003 or C++0x ) ? For the latter I still have much to learn since it is so new.
Both standards 2003 and C++0x. Plus you should look at compiler-specific extensions (maybe Clang has some introspection feature??). For example, SFINAE *might* allow to detect the private trait in C++0x but not in C++03 (I don't really know but a Boost introspection library should know and document that). Again, the idea for this "comparison" annex is to be as complete as possible (like a literature search when you write an academic paper). This might not change your library functionality at all but it will clearly position the features offered by your library with respect to what can be done (or will be possible) with C++ introspection and it will benefit your library users so they will know if a trait they are interested in introspecting can or not be introspected in C++.
Did you try to use the library? With what compiler? Did you have any problem?
-----------------------------------------------------------------------------
23. Yes, I compiled all the examples from the docs and played around with the library a bit more. I have used GCC 4.3.4 on CygWin and I had no issue.
How much effort did you put into your evaluation? A glance? A quick reading? In-depth study?
--------------------------------------------------------------------------------------------
24. I'd say in between a quick reading and an in-depth study. I spent about 12 hours total reading the docs, trying the examples, and writing this review.
Are you knowledgeable about the problem domain? -----------------------------------------------
25. I have used SFINAE before to introspect if a class has a given inner class to implement subcontracting for Boost.Contract. Furthermore, I have used template metaprogramming in a number of occasions.
Overall, I'd say that I am familiar with the problem domain but I am not an expert.
--Lorenzo
Thanks very much for your review and specific comments.
Thank you again for putting together useful libraries and keep up the good work! --Lorenzo

On 7/16/2011 3:02 PM, Lorenzo Caminiti wrote:
On Sun, Jul 10, 2011 at 11:59 PM, Edward Diener<eldiener@tropicsoft.com> wrote:
On 7/10/2011 7:59 PM, Lorenzo Caminiti wrote:
Review of Boost.TTI 2011-07-10 (Lorenzo Caminiti) =================================================
Do you think the library should be accepted as a Boost library? ---------------------------------------------------------------
Yes, in my opinion Boost.TTI should be accepted as a Boost library.
Appreciated !
Thank you for programming libraries that make my programming easier (like TTI and VMD).
Your welcome.
As I said, I am going to reply to all your comments here one by one.
Key points are:
1) I would essentially found this library useful as is.
2) The library should not expand its macros into the boost::tti namespace (I give a few reasons and suggest alternatives below).
3) The library uses too many macros to provide essentially the same functionality (with minor variations). This is confusing and the library macro API should be simplified (I suggest a possible simplification below).
I will answer each of your points below rather than generally answering 2) or 3) above.
My comments are all numbered and marked as follow: [MUST] If these comments are not addressed, I would no longer recommend to add this library into Boost. [WANT] I would like to see these comments addressed but I would still recommend to add this library into Boost even if these comments are not addressed. [NOTE] I do not feel strongly about these comments and the authors can ignore these comments if they wish to do so.
What is your evaluation of the design? --------------------------------------
1. [MUST] The library provides too many macros (with very similar functionality) which make the interface difficult to grasp. The authors should take some time to try to redesign and simply the library interface ideally reducing the number of macros.
I will give my reasons for each of the macros in answer to your suggestions below, but I completely agree that if the number of macros could be simplified and still offer the same basic functionality it should be done.
[WANT] I would reduce the macro API to the following 5 macros (no more, as I explain in the rest of the comments below):
HAS_TYPE(has_mytype, mytype) HAS_TEMPLATE(has_mytpl, [template(...) {class|struct}] mytpl)
I can look into combining the various template macros if it can be done. Currently there are three variations, disregarding the complex form of each macro. The variations are:
BOOST_TTI_HAS_TEMPLATE(name) BOOST_TTI_HAS_TEMPLATE_CHECK_PARAMS(name,pp-seq-of params) BOOST_TTI_VM_HAS_TEMPLATE_CHECK_PARAMS(name,variadic-sequence-of-params)
You would like to see a single macro, called BOOST_TTI_HAS_TEMPLATE, which could alternately take a pp-seq-of params or a variadic-sequence-of-params. I agree that would be wonderful if it could be done.
To do this the compiler must support variadic macros AFAICS. What if the
No, if the compiler does not support variadics then the macro will only accept the pp-sequence. If the compiler supports variadics then the macro will accepts both the pp-sequence and the variadic pp-tuple. It should be possible to program this using pp techniques similar to the ones I have used to program BOOST_LOCAL_FUNCTION_PARAMS (see http://svn.boost.org/svn/boost/sandbox/local/boost/local/function.hpp).
That clarified, I think we discussed this point enough in the other replies to this email thread. At the end I will use any API you decide to provide so case closed :)
end-user's compiler does not do so ? Even if the end-user's compiler supports variadic macros, how do I tell the difference between a pp-seq of params and a variadic-sequence of params ?
So here are my thoughts. If I supported the single macro for compilers which support variadic macros, I still need to support the two non-variadic macro versions for compilers which do not support variadic macros.
For the variadic macro version I can find out that is the variadic-sequence-of-params if it has more than one variadic parameter after the name. If it only has one variadic parameter after the name I can check if the parameter starts with a set of parens and, if it does, it is the pp-seq of params, else it is the variadic-sequence of params. I think this is doable. But I still can not see my way around dropping support completely for the non-variadic versions of this macro.
HAS_MEMBER_VARIABLE(has_myvar, [static] myvar) HAS_MEMBER_FUNCTION(has_myfunc, [static] myfunc)
I can easily combine BOOST_TTI_HAS_MEMBER_DATA and BOOST_TTI_HAS_STATIC_MEMBER_FUNCTION into HAS_MEMBER_VARIABLE, which covers either case, and BOOST_TTI_HAS_MEMBER_FUNCTION and BOOST_TTI_HAS_STATIC_MEMBER_FUNCTION into a HAS_MEMBER_FUNCTION, which cover either case. But then the end-user will lose the ability to distinguish between a 'member data/static member data' or 'member function/static member function'. Do you really think that is the correct thing to do just because you think there are too many macros ? I do not.
OTOH I do not mind adding the combined member data and member function macros as you suggested, while keeping what already exists, but then that adds more macros ( which does not bother me a bit ), which you do not like.
See below for my comments about the composite type functions.
MEMBER_TYPE(trait, name)
2. [MUST] Expanding the metafunctions within the boost::tti namespace presents a number of serious issues: a) If multiple part of the program (possibly independent libraries) use the TTI library to introspect the same name, the metafunction names will clash. b) The library macros can only be used at namespace scope. However, it should be possible to use the macros also at class scope so to define the introspection metafunctions as inner classes, etc (this is critical for example in my application for Boost.TTI where I use it to implement Boost.Contract and all Boost.Contract macros expand at class scope).
BTW, the docs should indicate within which scope the macros can be used. I think the macros should be used within namespace and class/struct scope. Unfortunately, I don't think there is a way to use the macros within local scope (e.g., within a function) because local classes cannot be templates. This should be documented.
The macros generate metafunctions, which are templates of a particular syntax ( nested 'type' member ). So wherever a template can occur is valid. They are no different from any other metafunction as determined by boost MPL. I really do not see the necessity of having to say much more, but I will put in a note to say the above. I will also mention, because of ODR, that the macros should be put within a namespace at the minimum and/or the traits parameter can be used to give the metafunction a distinct name within whatever scope the macro is used.
The authors should address these issues.
I totally agree with your criticism here and I will remove the generated macros from any namespace. Others have also mentioned the same thing and I immediately realized they were right when I read their reasoning.
[WANT] To address these issues, I would suggest to simply define the metafunctions within the enclosing scope. It will be the user's responsibility to use the macros within the correct scope (namespace, class, etc). For example:
template< class T> struct OurTemplateClass { BOOST_TTI_HAS_TYPE(has_mytype, _mytype) // also at class scope
void f() { std::cout<< has_mytype<T>::value<< std::endl; } };
This should also allow to remove all the GEN/GEN_BASE macros.
I can remove the GEN_BASE set but I would still keep the GEN set ( which would be the same as the current GEN_BASE set ) in order to provide an easy way to generate the metafunction name from the appropriate macro, without the end-user having to manually remember the algorithm by which I generate the metafunction name.
See below for my comments about generating the metafunction name.
3. [MUST] The library macros prefix the specified name with _ but this can create a symbol with double underscores __ which is reserved by C++ (e.g., HAS_TYPE(_my_type) creates a metafunction named boost::tti::has_type__my_type which is a reserved symbol). The authors should address this issue.
You have made a good point and I can simply remove the preceding '_' when generating the final metafunction name.
But then HAS_TYPE(mytype) generates the unreadable name has_typemytype :( Unfortunately, as a user of your library I won't think this is a good solution...
I am tempted to keep the name generation I already have, with the leading _, and tell the end-user that if the 'name' being introspected begins with an underscore ( _ ), then the traits form of each macro should be used to avoid a generated name with a double underscore ( __ ). The end-user should use the equivalent GEN macro to generate the resultant macro metafunction name rather than having to remember the naming convention I finally decide on. That is why the equivalent GEN macros were created.
[WANT] To address this issue (and also to reduce the number of macros eliminating the need for separate TRAIT macros), I would suggest to always ask the user to specify both the trait and the introspected name (not just the introspected name) and then use the trait to name the metafunction (as always, it is the user's responsibility to not use reserved names). For example:
HAS_TYPE(has_mytype, _mytype) // generates metafunc has_my_type
This should also allow to remove all the TRAIT macros.
You want to remove functionality for automatically generating a macro metafunction name just because you feel there are too many macros. I believe
No, it's for two reasons (1) the generated name can contain __ and (2) there are too many macros (not just (2)). As I said, if you address (1) by removing the _ prefix then the names will be unreadable:
HAS_TYPE(mytype) // generates has_typemytype
I think the name has_typemytype is unreadable. I will then always use the TRAIT macros to generate more readable names like has_type_mytype and making the automatic name generation functionality useless. However, if you can fully address (1) then (2) might not be a strong enough reason to remove the automatic name generation but how can you really address (1) in general?
Just to shared some ideas, I tough about the possibility to generate a name like has_type::mytype. For example, using an enclosing struct:
struct has_type { template< typename T> class mytype { ... }; // metafunc from your macro };
But then you cannot expand two macros HAS_TYPE(mytype) and HAS_TYPE(yourtype) within the same context because the enclosing struct name has_type will clash so I concluded this a very bad idea. Also you can't use a namespace has_type because of all the namespace issues we already discussed... too bad because if there was a way to automatically generate a name like has_type::mytype I think the automatic name generation functionality would be cool.
I do not want to get into enclosing structs, especially as the problem of an enclosing namespace has been pointed out to me.
that the automatic generation of the metafunction name is welcomed by metaprogrammers. The MPL macros BOOST_MPL_HAS_XXX_TEMPLATE_DEF/BOOST_MPL_HAS_XXX_TEMPLATE_NAMED_DEF and BOOST_MPL_HAS_XXX_TRAIT_DEF/BOOST_MPL_HAS_XXX_TRAIT_NAMED_DEF follow the scheme I have chosen.
4. [WANT] I really think that mixing () and<> parenthesis is confusing:
HAS_TEMPLATE_CHECK_PARAMS(MoreParameters, (class) (class) (int) (short) (class) (template<class)(int> class InnerTemplate) // confusing :( (class) )
IMO, this would be more readable as the following:
HAS_TEMPLATE_CHECK_PARAMS(MoreParameters, (class) (class) (int) (short) (class) (template( (class) (int) ) class InnerTemplate) // ok :) (class) )
I will look into this. It is obviously more difficult programming with the latter than the former, but it is probably doable although with much effort. It may not be worth the effort.
What the former syntax reflects is an exact transcription of the template parameters with each comma replaced by ')(' and a starting and ending parentheses. So for the template:
'template<class,class,int,class,template<class> class InnerTemplate,class,long> struct ManyParameters { }'
the parameters are:
'(class)(class)(int)(class)(template<class> class InnerTemplate)(class)(long)'
and all I had to do as an end-user was copy the template parameters, add a '(' at the beginning, add a ')' at the end, and change every ',' to a ')('. As a programmer I take the sequence and directly convert it to the template parameters via a BOOST_PP_SEQ_ENUM.
I think we discussed this well enough in previous replies to this email thread. Please try to think first of the syntax that your library users (your customers) will find most useful and don't think about how complex it will be to pp-program within your library. Again, at the end I will use any syntax you decide to provide.
5. [NOTE] There is no real need to use another macro ..._CHECK_PARAMS because HAS_TEMPLATE can be reused. This would reduce the number of macros. For example, with template parameters:
HAS_TEMPLATE( template( // gives the parameters (optional) (class) (class) (int) (short) (class) (template( (class) (int) ) class InnerTemplate) (class) ) struct MoreParameters // struct or class can be used here )
And the same macro without template parameters:
HAS_TEMPLATE(MoreParameters)
See above for my answer to this.
6. [NOTE] The same macros can accept both pp-sequences and variadic pp-tuples (when variadic macros are supported). This eliminates the VM macros reducing the number of different macros in the library API. For example:
HAS_TEMPLATE( template( class, class, int, short, class, template( class, int ) class InnerTemplate, // variadic commas class ) struct MoreParameters )
I know this uses template( class, int ) instead of template< class, int> but this way the syntaxes with and without variadics are unified and consistent (and more readable IMO). Alternatively, you can probably program the macro with variadic to be:
HAS_TEMPLATE( template< // template< > here class, class, int, short, class, template< class, int> class InnerTemplate, // template< > here class > struct MoreParameters )
But still keep the following syntax without variadics:
HAS_TEMPLATE( template( // template( ) here (class) (class) (int) (short) (class) (template( (class) (int) ) class InnerTemplate) // template( ) here (class) ) struct MoreParameters )
See above for my answer to this.
7. [WANT] Can the authors explain why the inner template parameter name InnerTemplate is needed while all other template parameter names are not needed? Is it really needed? Why I cannot do:
HAS_TEMPLATE( template( class, class, int, short, class, template( class, int ) class, // no name InnerTemplate class ) struct MoreParameters )
It should not be needed. Please try without it. If it does not work I will look and see why and attempt to correct it.
I didn't have time to try. However, can you please verify this and remove the InnerTemplate parameter name from the docs? (Or put a note in the docs that say why this parameter name is needed.) I got confused because the docs name this one parameter but not the other parameters...
I have verified it and it works without the inner template parameter name. One can include the inner template parameter in the template or not, one can include the inner template name in the macro or not, and the introspection works without problems. I will remove that inner template name in the examples in the docs and in my tests.
8. [NOTE] There is no need to use a different set of macros for static because the keyword static can be used to have the pp detect this case. This will reduce the number of different macros. For example:
HAS_STATIC_MEMBER_FUNCTION(has_static_f, f)
Can be replaced by:
HAS_MEMBER_FUNCTION(has_static_f, static f)
See above for my previous discussion on dropping the distinction between member functions and static member functions.
We discussed this well enough in other replies to this email thread. I totally respect your decision that [1] is more clear than [2]:
HAS_STATIC_MEMBER_FUNCTION(func) // [1] HAS_MEMBER_FUNCTION(static func) // [2]
However, I would like to offer the reflection that [2] is a more flexible API than [1]. Say your library is expanded to detect public, protected, and private and you can do that for both static and non-static member functions. Then you will have to provide lots of macros for all these combinations:
HAS_MEMBER_FUNCTION HAS_PUBLIC_MEMBER_FUNCTION HAS_PROTECTED_MEMBER_FUNCTION HAS_PRIVATE_MEMBER_FUNCTION HAS_STATIC_MEMBER_FUNCTION HAS_STATIC_PUBLIC_MEMBER_FUNCTION HAS_STATIC_PROTECTED_MEMBER_FUNCTION HAS_STATIC_PRIVATE_MEMBER_FUNCTION
Now say you can also detect virtual public, protected, or private member functions, you have to add another 4 macros for that too... Instead the other syntax will only and always use 1 macro:
HAS_MEMBER_FUNCTION( [public | protected | private] [static | virtual] func )
So the API [2] will never blowout if more traits can be introspected while [1] will blowout fast. That said, this is not a concern for your library right now because you can only introspect the one static trait.
You have made a good point. I will think about this further. The current problem is mainly that the macro metafunction generated depends on the difference between 'static' and 'non-static' member functions or 'static' and 'non-static' data members. I could generate a metafunction for both and then use a traits-like template parameter to distinguish between them, but that would mean some code bloat when unnecessary. A programmer would be paying for functionality he may not use. OTOH I do not like the idea of passing such decisions as macro parameters because that means more complicated macro syntax and I would like to keep the macros as simple as possible while letting the metafunctions absorb any complications. I am much less against additional macro names than you are. I see nothing wrong with a well-documented and large API, with a programmer understanding what has to be used for what needed functionality. I do understand your point about proliferating combinations.
9. [WANT] Why can't we always use the composite function syntax R (C::*)(A0, A1, ...)? This is similar to the preferred notation for Boost.Function so if possible it should be used instead of the other notation.
As I understand it, some compilers have troubles supporting the composite syntax. However, these compilers might not be able to support the TTI library all together. Unless there is evidence of compilers that can support TTI but not the composite function syntax, I think only the composite function notation should be provided.
This should also allow to remove all the COMP macros.
The reason for having both a composite syntax, which you like, and the non-composite syntax of individual types is:
1) The composite type syntax can be used when one has to pass a calling convention, or possible some compiler-specified function-like syntax, which the function_types 'tag' type does not support. I think this is absolutely necessary to have.
2) The individual type syntax is there so that MEMBER_TYPE can be used to pass a nested type which does not have to exist without causing a compiler error. I also thin this is absolutely necessary to have.
Please read the section called 'Nested Types' in the documentation to understand why MEMBER_TYPE is used. The ability to pass a nested type in the form of a MEMBER_TYPE as a function parameter is very important piece of functionality. Being able to do this for a function parameter type or for the function return type is something I do not want to eliminate.
Thank you for explaining this. I am still thinking about it... Could you please reply with an example of a MEMBER_TYPE can is used with the individual type syntax but fails if passed to the composite syntax? That will help me a lot in fully understanding this issue.
As one typical example, you have a type T and one of the types in a function signature is a possible nested type of T called NestedType and you are introspecting for a static function of T whose signature is 'int SomeStaticFunction(T::NestedType)'. If you use composite syntax: BOOST_TTI_HAS_COMP_STATIC_MEMBER_FUNCTION(SomeStaticFunction) BOOST_TTI_HAS_COMP_STATIC_MEMBER_FUNCTION_GEN(SomeStaticFunction)<T,int SomeStaticFunction(T::NestedType)>::value you will get a compiler error if T::NestedType does not exist but if you use individual type syntax: BOOST_TTI_MEMBER_TYPE(NestedType) BOOST_TTI_HAS_STATIC_MEMBER_FUNCTION(SomeStaticFunction) BOOST_TTI_HAS_STATIC_MEMBER_FUNCTION_GEN(SomeStaticFunction)<T,int,boost::mpl::vector<BOOST_TTI_MEMBER_TYPE_GEN(NestedType)::type><T>
::value
you will not get a compiler error but the value will be false if T::NestedType does not exist, which is really what you want. Of course T::Nested type may exist but the static member function you are introspecting may not exist, and the value will still be false. But you will not get a compiler error in either case.
10. [NOTE] I think "member variable" is a more accepted name that "member data"-- isn't it? If so, I'd rename MEMBER_DATA to MEMBER_VARIABLE.
I can understand your preference. I will consider it.
11. [WANT] Is it possible to have some sort of composite syntax for member variables?
There is no reason to have a composite syntax for member variables. A member variable is a single type.
As I said in a previous reply (1) the C++ standard name is data member (so HAS_MEMBER_DATA or HAS_DATA_MEMBER are good names as far as I am concerned) and (2) there exist a composite data member syntax:
struct c { int x; };
int c::* // type of pointer to int data member of c
So:
HAS_MEMBER_DATA(x) // [1] has_x<c, int> // 2 tparams
HAS_COMP_MEMBER_DATA(x) // [2] has_comp_x<int c::*> // 1 (composite) tparam
That said if you think there is no reason to support the composite data member syntax [2], that's fine. I'd add a note to the docs explaining why the composite syntax is supported for member functions but not for data members.
I will add that to the docs.
I remember reading something about this for overloading the operator ->* to access member variables (as well as calling member functions) but I can't double check right now... can the authors look into this? For example:
HAS_MEMBER_VARIABLE(has_number, number)
has_number<T::short> // composite form for member variable?
If there exists a composite form for member variables, I would like the generated metafunctions to use it instead of the plain form (so to be consistent with the MEMBER_FUNCTION macros-- see comment above).
12. [WANT] Are the metafunction MTFC macros really needed? The docs say they reduce compile-time (compared to using MPL placeholders) but no evidence is shown to support that...
Extra macros complicate the library API so if they are provided for reducing compile-time there should be some benchmarking showing their benefits. If not, these macros should be removed.
[NOTE] If these macros are shown to be beneficial, I'd rename them with a METAFUNC postfix because I find it more readable. For example:
HAS_TYPE_METAFUNC HAS_MEMBER_FUNCTION_METAFUNC
I supplied them merely as a convenience. In an early mailing list message about the TTI library from Dave Abrahams, before this review, he suggested that passing metafunctions as data as a metafunction class would generally be faster than passing them via placeholder expressions. I do not mind eliminating them if it seen as overkill.
If there is evidence (compile-time data and possibly some explanation) of that MTFC have faster compile-time, leave the macros. However, I thinks you either (1) measure the compile-times add the evidence in the docs or (2) you remove the MTFC macros.
Having the MTFC macros does not hurt anything. There is no reason to not supply them purely as a convenience.
13. [WANT] Are the nullary metafunctions really needed?
Functionally, no, which the documentation explicitly explains. Syntactically I feel they are much easier to use once they are understood.
The docs say they simplify the syntax but no side-by-side example comparing the syntax with and without the nullary type metafunctiosn is provided...
Unless their benefit is clearly shown, the nullary metafunctions should be remove to simplify the library API.
I will add side by side examples showing the simpler syntax of using the nullary metafunctions. I do show the different syntaxes for similar situations in the doc, but not side by side.
Can you please reply to this email with a short example that compares the two syntaxes so we can all take a look at it?
Why not just ignore them if you do not like their syntax ? After all tghey
Because as a new user of your library I think "are they important?", "shall I learn them?", "do I need/want their simpler syntax?". So if they really offer a benefit (even just syntactical), they should be there, just illustrate their benefit better.
There are sections in the doc about "Nullary Type Metafunctions" and "Using the Nullary Type Metafunctions". I will work on expanding the documentation in these sections, perhaps adding some more sections, so that others understand the syntactical advantage of using the nullary metafunctions if they want to do so.
are just a set of metafunctions, which no one has to learn to use if they do not want to do so. They do not interfere with anything else in the library and they allow specifying nested types in a syntactically easier way.
14. [NOTE] I'd fully spell the header file names to improve readability and be consistent with the macro names (which are correctly fully spelled). For example, "member_function.hpp" instead of "mem_fun.hpp".
I can do that, and probably will. You have a good point.
15. [NOTE] I'd rather use an actual name for the library instead of the cryptic acronym TTI (but I personally don't like the widely used MPL neither so maybe it's just me). Maybe "intro" (for introspection), or "mirror" (look at yourself), or "soul" (look into your soul), or "psycho" (look into your person) ;) would be better names...
Where would you like to see the longer name ? I certainly do not mind calling the library Type Traits Introspection but that is quite a mouthful. Like MPL ( for Metaprogramming Library ), TTI is easier to remember and refer to.
What is your evaluation of the implementation? ----------------------------------------------
16. I did not look at the implementation.
What is your evaluation of the documentation? ---------------------------------------------
17. [WANT] I'd add a "Motivating Example" in the Introduction section to very briefly illustrate the library functionality (probably right after the bullet list on the library functionalities). I had to go all the way into the Nested Types section to start seeing some code... (I was motivated just because I knew what the library does and I've used MPL_XXX macros with SFINAE before).
I totally agree with you. I intend to revamp the introductory material to make it simpler and easier to understand what the library can do, and present some basic motivating examples.
18. [NOTE] I don't think you need a space before "?" in English (see "Why the TTI Library ?", etc).
You are right. I will change it. It is just my style but unnecessary.
19. [WANT] Typo in "depending on how many parameters are bring passed".
Corrected ! Thanks !
What is your evaluation of the potential usefulness of the library? -------------------------------------------------------------------
20. [NOTE] The library is very useful as is. For example, I use a similar introspection technique in Boost.Contract as part of a mechanism to check if a base class has a virtual function that is being overridden so to automatically subcontract from such a base class function.
21. [WANT] I think the docs should add an annex with a complete list of all traits that would ideally be introspected even if they cannot actually be introspected. For example, a table could list all traits that would be good to introspect and then for each trait say "introspected by this library", or "cannot be introspected in C++ because...", etc. For example, Boost.Contract could use the ability to check if a function is public, protected, or private to simplify its macro syntax (because only public functions shall check class invariants).
Possible traits for introspection I can think of are: is public, is protected, is private, is template, has these template parameters, is explicit, is inline, is extern, is static, is virtual, is const member, is volatile member, has these exception specifications (throw), any more?
I think your possible list is too arbitrary. Most anything can be added here.
No, my list is not arbitrary but it tries to include _all_ the traits in a function (free, member, constructor, and destruct) declaration:
func_signature_: // for free functions, member functions, constructors, and destructors [public | protected | private] [[export] [template< template_param, ...>] [explicit] [inline] [extern] [static] [virtual] [result_type_] func_name_ ( func_params_ ) [const] [volatile] [throw( [expections_] )]
Also: 1) How about classes? For example, a metafunction to introspect "is B a protected base of class C?" 2) How about namespaces? For example, a metafunction to introspect "is f an free function in namespace n?"
It is true that most anything can be added here. However, the traits supported by TTI are actually arbitrary. Why there is a matafunction for "is f a static member of class C?" but not for "is f a virtual member of class C?". From a library user prospective, I might be interested in the static trait as much or as well as in the virtual trait. However, TTI now introspects the static trait but not the virtual trait and that seems arbitrary for the user. If other traits cannot be introspected (like virtual, public, etc), that is fine but you should document somewhere that TTI does not introspect them not because we "forgot" these other traits but because it is not possible to introspect them in C++.
Also this annex should serve as the "total" reference for C++ introspection. If I want to know if a public member function can be introspected in C++, I should be able to look at your library and either find the API that introspects the public trait or find that such a trait cannot be introspected. I think you need to address all the other traits (maybe just saying they cannot be introspected) otherwise you library is not a general introspection library but it is an introspection library only for the 4 traits it can introspect.
The macros provided are not arbitrary. They are a core set of introspection macros for each type of inner element. That you can dream up more possibilities is fine, but it is not the responsibility of my library to tell you about all the possibilities and to then tell you that the library only does the basic set. Any library design is finite and chooses what it wants to do. I welcome the knowledge of other possibilities but that does not mean the library can do them or even try to do them. At that rate no library will ever be finished.
22. [WANT] I'd add an annex to the docs to compare this library with other libraries (e.g., the "mirror" library?) that exist out there for introspection (i.e., some sort of literature review).
if there were an existing Boost library I might do it.
Why would you compare Boost.TTI only with other Boost libraries? You should do a literature search on C++ introspection in general and compare Boost.TTI with *all* known C++ introspection library even/especially if they are not in Boost.
I disagree with you. It is not the responsibility of a library developer to investigate and document every other possibile similar library. I can understand that if there were a C++ standard library or a Boost library which offered similar features to what another Boost library is attempting to provide, then it would be good for the developer to compare his library to what is already exists in that domain to illustrate the advantages and disadvantages of one's own approach.
I would also comment on possible C++ standard extensions or compiler specific support for introspection.
Which C++ standard ( 2003 or C++0x ) ? For the latter I still have much to learn since it is so new.
Both standards 2003 and C++0x. Plus you should look at compiler-specific extensions (maybe Clang has some introspection feature??). For example, SFINAE *might* allow to detect the private trait in C++0x but not in C++03 (I don't really know but a Boost introspection library should know and document that).
Again, the idea for this "comparison" annex is to be as complete as possible (like a literature search when you write an academic paper). This might not change your library functionality at all but it will clearly position the features offered by your library with respect to what can be done (or will be possible) with C++ introspection and it will benefit your library users so they will know if a trait they are interested in introspecting can or not be introspected in C++.
I can see this, but I really know little, except for extended SFINAE in C++0x, which could be mentioned. I will mention that in my docs. if there are any other features, even compiler specific features, which aid in the introspection of inner elements, I would be glad to be informed about them and use them. A Boost library is not an academic paper, and I have the greatest respect for academic scholarship. There is just so much information that the library developer should be expected to present to the end-user.
Did you try to use the library? With what compiler? Did you have any problem?
-----------------------------------------------------------------------------
23. Yes, I compiled all the examples from the docs and played around with the library a bit more. I have used GCC 4.3.4 on CygWin and I had no issue.
How much effort did you put into your evaluation? A glance? A quick reading? In-depth study?
--------------------------------------------------------------------------------------------
24. I'd say in between a quick reading and an in-depth study. I spent about 12 hours total reading the docs, trying the examples, and writing this review.
Are you knowledgeable about the problem domain? -----------------------------------------------
25. I have used SFINAE before to introspect if a class has a given inner class to implement subcontracting for Boost.Contract. Furthermore, I have used template metaprogramming in a number of occasions.
Overall, I'd say that I am familiar with the problem domain but I am not an expert.
--Lorenzo
Thanks very much for your review and specific comments.
Thank you again for putting together useful libraries and keep up the good work!
Like all software developers and designers of any expertise I take great pride in doing the best work I can. Eddie

On Sun, Jul 17, 2011 at 10:05 AM, Edward Diener <eldiener@tropicsoft.com> wrote:
On 7/16/2011 3:02 PM, Lorenzo Caminiti wrote:
12. [WANT] Are the metafunction MTFC macros really needed? The docs say they reduce compile-time (compared to using MPL placeholders) but no evidence is shown to support that...
Extra macros complicate the library API so if they are provided for reducing compile-time there should be some benchmarking showing their benefits. If not, these macros should be removed.
[NOTE] If these macros are shown to be beneficial, I'd rename them with a METAFUNC postfix because I find it more readable. For example:
HAS_TYPE_METAFUNC HAS_MEMBER_FUNCTION_METAFUNC
I supplied them merely as a convenience. In an early mailing list message about the TTI library from Dave Abrahams, before this review, he suggested that passing metafunctions as data as a metafunction class would generally be faster than passing them via placeholder expressions. I do not mind eliminating them if it seen as overkill.
If there is evidence (compile-time data and possibly some explanation) of that MTFC have faster compile-time, leave the macros. However, I thinks you either (1) measure the compile-times add the evidence in the docs or (2) you remove the MTFC macros.
Having the MTFC macros does not hurt anything. There is no reason to not supply them purely as a convenience.
As a user of your library, how would I decide if I should use MTFC or not? The docs say MTFC might be faster but the docs don't say of how much, for which compiler, etc. Please keep your users in mind, if you provide the MTFC functionality to your users, you need to provide them also with all the information they need to make the informed decision of when to use such functionality or not.
13. [WANT] Are the nullary metafunctions really needed?
Functionally, no, which the documentation explicitly explains. Syntactically I feel they are much easier to use once they are understood.
The docs say they simplify the syntax but no side-by-side example comparing the syntax with and without the nullary type metafunctiosn is provided...
Unless their benefit is clearly shown, the nullary metafunctions should be remove to simplify the library API.
I will add side by side examples showing the simpler syntax of using the nullary metafunctions. I do show the different syntaxes for similar situations in the doc, but not side by side.
Can you please reply to this email with a short example that compares the two syntaxes so we can all take a look at it?
Why not just ignore them if you do not like their syntax ? After all tghey
Because as a new user of your library I think "are they important?", "shall I learn them?", "do I need/want their simpler syntax?". So if they really offer a benefit (even just syntactical), they should be there, just illustrate their benefit better.
There are sections in the doc about "Nullary Type Metafunctions" and "Using the Nullary Type Metafunctions". I will work on expanding the documentation in these sections, perhaps adding some more sections, so that others understand the syntactical advantage of using the nullary metafunctions if they want to do so.
Again, can you please reply to this email with a short example that compares the two syntaxes so we can all (i.e., all Boosters) take a look at it?
22. [WANT] I'd add an annex to the docs to compare this library with other libraries (e.g., the "mirror" library?) that exist out there for introspection (i.e., some sort of literature review).
if there were an existing Boost library I might do it.
Why would you compare Boost.TTI only with other Boost libraries? You should do a literature search on C++ introspection in general and compare Boost.TTI with *all* known C++ introspection library even/especially if they are not in Boost.
I disagree with you. It is not the responsibility of a library developer to investigate and document every other possibile similar library. I can understand that if there were a C++ standard library or a Boost library which offered similar features to what another Boost library is attempting to provide, then it would be good for the developer to compare his library to what is already exists in that domain to illustrate the advantages and disadvantages of one's own approach.
What do other Boosters think of this?
I would also comment on possible C++ standard extensions or compiler specific support for introspection.
Which C++ standard ( 2003 or C++0x ) ? For the latter I still have much to learn since it is so new.
Both standards 2003 and C++0x. Plus you should look at compiler-specific extensions (maybe Clang has some introspection feature??). For example, SFINAE *might* allow to detect the private trait in C++0x but not in C++03 (I don't really know but a Boost introspection library should know and document that).
Again, the idea for this "comparison" annex is to be as complete as possible (like a literature search when you write an academic paper). This might not change your library functionality at all but it will clearly position the features offered by your library with respect to what can be done (or will be possible) with C++ introspection and it will benefit your library users so they will know if a trait they are interested in introspecting can or not be introspected in C++.
I can see this, but I really know little, except for extended SFINAE in C++0x, which could be mentioned. I will mention that in my docs. if there are any other features, even compiler specific features, which aid in the introspection of inner elements, I would be glad to be informed about them and use them.
A Boost library is not an academic paper, and I have the greatest respect for academic scholarship. There is just so much information that the library developer should be expected to present to the end-user.
What do other Boosters think also of this? Thanks, --Lorenzo

On Jul 17, 2011, at 1:26 PM, Lorenzo Caminiti wrote:
On Sun, Jul 17, 2011 at 10:05 AM, Edward Diener <eldiener@tropicsoft.com> wrote:
On 7/16/2011 3:02 PM, Lorenzo Caminiti wrote:
22. [WANT] I'd add an annex to the docs to compare this library with other libraries (e.g., the "mirror" library?) that exist out there for introspection (i.e., some sort of literature review).
if there were an existing Boost library I might do it.
Why would you compare Boost.TTI only with other Boost libraries? You should do a literature search on C++ introspection in general and compare Boost.TTI with *all* known C++ introspection library even/especially if they are not in Boost.
I disagree with you. It is not the responsibility of a library developer to investigate and document every other possibile similar library. I can understand that if there were a C++ standard library or a Boost library which offered similar features to what another Boost library is attempting to provide, then it would be good for the developer to compare his library to what is already exists in that domain to illustrate the advantages and disadvantages of one's own approach.
What do other Boosters think of this?
I would hope that out of intellectual curiosity Eddie would want to look at other solutions to the problem, especially now that his library is "complete" and accepted. But I think it is the community's responsibility to bring up comparisons. E.g. I hoped that Matus Chochlik and Matt Calabrese would bring some perspective to the review, if not actually vote.

On 7/17/2011 2:12 PM, Gordon Woodhull wrote:
On Jul 17, 2011, at 1:26 PM, Lorenzo Caminiti wrote:
On Sun, Jul 17, 2011 at 10:05 AM, Edward Diener<eldiener@tropicsoft.com> wrote:
On 7/16/2011 3:02 PM, Lorenzo Caminiti wrote:
22. [WANT] I'd add an annex to the docs to compare this library with other libraries (e.g., the "mirror" library?) that exist out there for introspection (i.e., some sort of literature review).
if there were an existing Boost library I might do it.
Why would you compare Boost.TTI only with other Boost libraries? You should do a literature search on C++ introspection in general and compare Boost.TTI with *all* known C++ introspection library even/especially if they are not in Boost.
I disagree with you. It is not the responsibility of a library developer to investigate and document every other possibile similar library. I can understand that if there were a C++ standard library or a Boost library which offered similar features to what another Boost library is attempting to provide, then it would be good for the developer to compare his library to what is already exists in that domain to illustrate the advantages and disadvantages of one's own approach.
What do other Boosters think of this?
I would hope that out of intellectual curiosity Eddie would want to look at other solutions to the problem, especially now that his library is "complete" and accepted. But I think it is the community's responsibility to bring up comparisons. E.g. I hoped that Matus Chochlik and Matt Calabrese would bring some perspective to the review, if not actually vote.
I am perfectly willing to look at other ideas and implementations to improve my own library in any way that I can. I am perfectly willing to have others contribute better techniques to my library even though I feel strongly that the design should be my own. But I do not understand the need to comment on other libraries in the documentation for my own unless another library already is considered mainstream and I am trying to point out the advantages of my library as opposed to another with much the same functionality. I really do not know the libraries by Matus Chochlik and Matt Calabrese very well or what relationship they have to TTI. Surely if the TTI library is well understood in its basic functionality by clear documentation, others can compare it against other solutions which are also documented well.

On Sun, Jul 17, 2011 at 8:12 PM, Gordon Woodhull <gordon@woodhull.com> wrote:
On Jul 17, 2011, at 1:26 PM, Lorenzo Caminiti wrote:
On Sun, Jul 17, 2011 at 10:05 AM, Edward Diener <eldiener@tropicsoft.com> wrote:
On 7/16/2011 3:02 PM, Lorenzo Caminiti wrote:
22. [WANT] I'd add an annex to the docs to compare this library with other libraries (e.g., the "mirror" library?) that exist out there for introspection (i.e., some sort of literature review).
I disagree with you. It is not the responsibility of a library developer to investigate and document every other possibile similar library. I can understand that if there were a C++ standard library or a Boost library which offered similar features to what another Boost library is attempting to provide, then it would be good for the developer to compare his library to what is already exists in that domain to illustrate the advantages and disadvantages of one's own approach.
What do other Boosters think of this?
I would hope that out of intellectual curiosity Eddie would want to look at other solutions to the problem, especially now that his library is "complete" and accepted. But I think it is the community's responsibility to bring up comparisons. E.g. I hoped that Matus Chochlik and Matt Calabrese would bring some perspective to the review, if not actually vote.
From the little browsing around the docs that I've done, I would vote for inclusion into Boost, but since I didn't have the time to try the library or look at the code
I'm very sorry that both some personal and work-related things have kept me from looking closely and writing a review on Edward's library (and even from doing anything introspection/reflection related myself the last month or so). I'm very interested in Boost.Introspection since it is (I think) complementary to the Mirror reflection utilities I'm working on. From my point of view it is a very useful library and if I may very briefly compare it to Mirror then Introspection is useful when you know what you are looking for. Mirror is more about seeing what "is out there" (and doing something with it). this "vote" would should not be considered as a real review. Best, Matus

On 7/17/2011 1:26 PM, Lorenzo Caminiti wrote:
On Sun, Jul 17, 2011 at 10:05 AM, Edward Diener<eldiener@tropicsoft.com> wrote:
On 7/16/2011 3:02 PM, Lorenzo Caminiti wrote:
12. [WANT] Are the metafunction MTFC macros really needed? The docs say they reduce compile-time (compared to using MPL placeholders) but no evidence is shown to support that...
Extra macros complicate the library API so if they are provided for reducing compile-time there should be some benchmarking showing their benefits. If not, these macros should be removed.
[NOTE] If these macros are shown to be beneficial, I'd rename them with a METAFUNC postfix because I find it more readable. For example:
HAS_TYPE_METAFUNC HAS_MEMBER_FUNCTION_METAFUNC
I supplied them merely as a convenience. In an early mailing list message about the TTI library from Dave Abrahams, before this review, he suggested that passing metafunctions as data as a metafunction class would generally be faster than passing them via placeholder expressions. I do not mind eliminating them if it seen as overkill.
If there is evidence (compile-time data and possibly some explanation) of that MTFC have faster compile-time, leave the macros. However, I thinks you either (1) measure the compile-times add the evidence in the docs or (2) you remove the MTFC macros.
Having the MTFC macros does not hurt anything. There is no reason to not supply them purely as a convenience.
As a user of your library, how would I decide if I should use MTFC or not? The docs say MTFC might be faster but the docs don't say of how much, for which compiler, etc. Please keep your users in mind, if you provide the MTFC functionality to your users, you need to provide them also with all the information they need to make the informed decision of when to use such functionality or not.
Are not users allowed to try one way or the other and then test if their compile times are faster or slower ? Jeffrey Hellrung has pointed out that boost::mpl::quote is an easy way of creating a metafunction class from a metafunction so, unless I hear otherwise from reviewers who object, I will probably drop the MTFC macros. I am not guarantee that I will do that since in my own tests I use it extensively, along with placeholder expressions, and I find my syntax easy to use, but if I do decide to keep them around I will section any explanation about them off from the main documentation. I still am a bit intrigued that so many users of a library feel that added macro sets ( like the MTFC macros and the GEN macros) or alternative functionality ( like the nullary metafunctions ), which could be ignored by anybody who wishes without losing any of the basic functionality of the macro metafunctions, somehow detract from the ability to use or understand the library.
13. [WANT] Are the nullary metafunctions really needed?
Functionally, no, which the documentation explicitly explains. Syntactically I feel they are much easier to use once they are understood.
The docs say they simplify the syntax but no side-by-side example comparing the syntax with and without the nullary type metafunctiosn is provided...
Unless their benefit is clearly shown, the nullary metafunctions should be remove to simplify the library API.
I will add side by side examples showing the simpler syntax of using the nullary metafunctions. I do show the different syntaxes for similar situations in the doc, but not side by side.
Can you please reply to this email with a short example that compares the two syntaxes so we can all take a look at it?
Why not just ignore them if you do not like their syntax ? After all tghey
Because as a new user of your library I think "are they important?", "shall I learn them?", "do I need/want their simpler syntax?". So if they really offer a benefit (even just syntactical), they should be there, just illustrate their benefit better.
There are sections in the doc about "Nullary Type Metafunctions" and "Using the Nullary Type Metafunctions". I will work on expanding the documentation in these sections, perhaps adding some more sections, so that others understand the syntactical advantage of using the nullary metafunctions if they want to do so.
Again, can you please reply to this email with a short example that compares the two syntaxes so we can all (i.e., all Boosters) take a look at it?
From the docs ( it is really there but separated right now ) : struct T { struct AType { struct BType { struct CType { struct FindType { }; } }; }; }; BOOST_TTI_MEMBER_TYPE(FindType) BOOST_TTI_MEMBER_TYPE(AType) BOOST_TTI_MEMBER_TYPE(BType) BOOST_TTI_MEMBER_TYPE(CType) With macro metafunctions our syntax for creating a nested type called MyFindType which could refer to FindType is: typedef typename boost::tti::member_type_FindType < typename boost::tti::member_type_CType < typename boost::tti::member_type_BType < typename boost::tti::member_type_AType < T >::type >::type >::type
::type MyFindType;
With nullary type metafunctions the syntax to create a nested nullary type metafuncion which could refer to FindType is: typedef boost::tti::mf_member_type < boost::tti::member_type_FindType<_>, boost::tti::mf_member_type < boost::tti::member_type_CType<_>, boost::tti::mf_member_type < boost::tti::member_type_BType<_>, boost::tti::member_type_AType < T > > >
MyFindType;
I think the nullary type syntax is cleaner syntactically and easier to use. There may be a better solution for this sort of thing, but I am looking for simplicity. The whole idea, syntactically, of the nullary type metafunctions is that one passes around the metafunction itself rather than its nested type, so there is much less of the ::type in the syntax. It does involve using a separate set of boost::tti::mf_xxx metafunctions and passing metafunctions as data, but I feel that the syntactical gain is worth it. I really will update my documentation so that I will compare the macro metafunction and nullary type metafunction usage together when dealing with all of the cases of using the non-composite macro metafunctions. Eddie

On Jul 17, 2011, at 4:56 PM, Edward Diener wrote:
I still am a bit intrigued that so many users of a library feel that added macro sets ( like the MTFC macros and the GEN macros) or alternative functionality ( like the nullary metafunctions ), which could be ignored by anybody who wishes without losing any of the basic functionality of the macro metafunctions, somehow detract from the ability to use or understand the library.
I just found that it made reading the documentation rather daunting for what should be a pretty easy-to-understand library. Probably as people start using the library you'll see that most people use one set or another and you'll be able to adjust the docs to say "you'll probably want to do this, but there are a couple other ways to do it." Maybe it's just a case for a quick-start tutorial. (It surprises me to hear myself saying that.)

On 7/17/2011 5:06 PM, Gordon Woodhull wrote:
On Jul 17, 2011, at 4:56 PM, Edward Diener wrote:
I still am a bit intrigued that so many users of a library feel that added macro sets ( like the MTFC macros and the GEN macros) or alternative functionality ( like the nullary metafunctions ), which could be ignored by anybody who wishes without losing any of the basic functionality of the macro metafunctions, somehow detract from the ability to use or understand the library.
I just found that it made reading the documentation rather daunting for what should be a pretty easy-to-understand library. Probably as people start using the library you'll see that most people use one set or another and you'll be able to adjust the docs to say "you'll probably want to do this, but there are a couple other ways to do it."
Maybe it's just a case for a quick-start tutorial. (It surprises me to hear myself saying that.)
I am intent on reworking the documentation to make it easier to understand and more gradual from simple to difficult. Hopefully that will put off less people who can ignore what they view as nut usable for them. Eddie

on Sun Jul 17 2011, Edward Diener <eldiener-AT-tropicsoft.com> wrote:
I think the nullary type syntax is cleaner syntactically and easier to use. There may be a better solution for this sort of thing, but I am looking for simplicity.
The whole idea, syntactically, of the nullary type metafunctions is that one passes around the metafunction itself rather than its nested type, so there is much less of the ::type in the syntax. It does involve using a separate set of boost::tti::mf_xxx metafunctions and passing metafunctions as data, but I feel that the syntactical gain is worth it.
I really will update my documentation so that I will compare the macro metafunction and nullary type metafunction usage together when dealing with all of the cases of using the non-composite macro metafunctions.
I will admit to not knowing any of the background here, so what I'm about to say may be totally irrelevant but... One can build a completely lazy MPL if you say that everything has to be a metafunction: all types are wrapped in nullary metafunctions before they are used, so you don't reach in and grab the nested ::type until you are ready to get the final result of your computation. Vesa Karvonen was the first one to do this IIUC. Unfortunately my experiments have revealed that if you rely on this idiom everywhere you get horrible compile-time performance. FWIW-ly y'rs, -- Dave Abrahams BoostPro Computing http://www.boostpro.com

On 7/17/2011 5:53 PM, Dave Abrahams wrote:
on Sun Jul 17 2011, Edward Diener<eldiener-AT-tropicsoft.com> wrote:
I think the nullary type syntax is cleaner syntactically and easier to use. There may be a better solution for this sort of thing, but I am looking for simplicity.
The whole idea, syntactically, of the nullary type metafunctions is that one passes around the metafunction itself rather than its nested type, so there is much less of the ::type in the syntax. It does involve using a separate set of boost::tti::mf_xxx metafunctions and passing metafunctions as data, but I feel that the syntactical gain is worth it.
I really will update my documentation so that I will compare the macro metafunction and nullary type metafunction usage together when dealing with all of the cases of using the non-composite macro metafunctions.
I will admit to not knowing any of the background here, so what I'm about to say may be totally irrelevant but...
One can build a completely lazy MPL if you say that everything has to be a metafunction: all types are wrapped in nullary metafunctions before they are used, so you don't reach in and grab the nested ::type until you are ready to get the final result of your computation. Vesa Karvonen was the first one to do this IIUC. Unfortunately my experiments have revealed that if you rely on this idiom everywhere you get horrible compile-time performance.
What is IIUC ? I did not add the nullary type metafunctions for "laziness" but just as a syntactical convenience. I hope others realize that they can use them or ignore them as they see fit and if they do slow down compile times they should be ignored. Eddie

on Sun Jul 17 2011, Edward Diener <eldiener-AT-tropicsoft.com> wrote:
On 7/17/2011 5:53 PM, Dave Abrahams wrote:
One can build a completely lazy MPL if you say that everything has to be a metafunction: all types are wrapped in nullary metafunctions before they are used, so you don't reach in and grab the nested ::type until you are ready to get the final result of your computation. Vesa Karvonen was the first one to do this IIUC. Unfortunately my experiments have revealed that if you rely on this idiom everywhere you get horrible compile-time performance.
What is IIUC ?
"if I understand correctly"
I did not add the nullary type metafunctions for "laziness" but just as a syntactical convenience. I hope others realize that they can use them or ignore them as they see fit and if they do slow down compile times they should be ignored.
Again, I don't know what you're actually doing here or if it's the same as what I described above. However, if you *are* doing things as I described, whatever your purpose in doing so, my point is that if you do it consistently, you /get/ laziness, /and/ you get its performance implications. -- Dave Abrahams BoostPro Computing http://www.boostpro.com

Dave Abrahams wrote:
on Sun Jul 17 2011, Edward Diener <eldiener-AT-tropicsoft.com> wrote:
I think the nullary type syntax is cleaner syntactically and easier to use. There may be a better solution for this sort of thing, but I am looking for simplicity.
The whole idea, syntactically, of the nullary type metafunctions is that one passes around the metafunction itself rather than its nested type, so there is much less of the ::type in the syntax. It does involve using a separate set of boost::tti::mf_xxx metafunctions and passing metafunctions as data, but I feel that the syntactical gain is worth it.
I really will update my documentation so that I will compare the macro metafunction and nullary type metafunction usage together when dealing with all of the cases of using the non-composite macro metafunctions.
I will admit to not knowing any of the background here, so what I'm about to say may be totally irrelevant but...
One can build a completely lazy MPL if you say that everything has to be a metafunction: all types are wrapped in nullary metafunctions before they are used, so you don't reach in and grab the nested ::type until you are ready to get the final result of your computation. Vesa Karvonen was the first one to do this IIUC. Unfortunately my experiments have revealed that if you rely on this idiom everywhere you get horrible compile-time performance.
FWIW-ly y'rs,
Does this mean that if I use the nullary metafunciton macros to gain syntactical convenience, I will pay in compile-time performance? Again, this should be clarified and _quantified_ in the docs so as a user I can make an informed choice when you offer multiple choices for the same functionality. For example, the TTI authors should please measure and compare compile-times within and without nullary metafunctions for some version of MVSC and GCC and add it to the docs (and please do the same of MTFC). Thanks, --Lorenzo -- View this message in context: http://boost.2283326.n4.nabble.com/TTI-Review-tp3658414p3675578.html Sent from the Boost - Dev mailing list archive at Nabble.com.

On Sun, Jul 17, 2011 at 7:05 AM, Edward Diener <eldiener@tropicsoft.com>wrote:
I am much less against additional macro names than you are. I see nothing wrong with a well-documented and large API, with a programmer understanding what has to be used for what needed functionality.
I think the therein lies the concern: a large API makes it more difficult for the programmer to understand what is and is not relevant for the task at hand. Having the MTFC macros does not hurt anything. There is no reason to not
supply them purely as a convenience.
The reason not to supply them is that it contributes unnecessarily to API bloat. If Boost.TypeTraits supplied metafunction classes for all its metafunctions, I bet people would be making noise :) Regarding comments about, e.g., a literature search and an exhaustive comparison between other libraries (I'll refrain from quoting), it would be nice, and the more we know what we can do and cannot do with respect to non-intrusive compile-time introspection, the better. It's something that should be seamlessly addable in the future if deemed important enough. - Jeff
participants (11)
-
Dave Abrahams
-
Edward Diener
-
Gordon Woodhull
-
Jeffrey Lee Hellrung, Jr.
-
Joel falcou
-
lcaminiti
-
Lorenzo Caminiti
-
Matus Chochlik
-
Nathan Ridge
-
Stewart, Robert
-
Vicente Botet