
Hi Vicente, Thanks for diving into our library.
Note that I have just read the introduction of the documentation and I find the it quite clear.
Good to hear.
Some words about SNIFAE and partial specialization:
I've no problem to rephrase the documentation-section about SFINAE or even to omit it. The section documents our choice for tag dispatching, but it might be not necessary to do it in this detail. I've also no problems with SFINAE in general, it is just a preference for usage in more complex libraries like GGL. We've used SFINAE in the past, for about half a year, in GGL. However, we did have much problems with it, getting it all right and compiling it on all compilers. We especially did have troubles with the boost concept checking in combination with sfinae (maybe I should add that). Dave Abrahams wrote about this (I quote here from a mail in january 2009):
Barend: (...) This works perfectly and distinguishes all geometry types at compile time, as long as the library or the developer provides the meta function geometry_type<T>::type which is currently implemented as an enumeration of TYPE_POINT, etc.
Dave: Seems like you might be better off using tag dispatching...
We went over to tag dispatching and all those problems disappeared. Maybe I should add (if the section is not going to be omitted) that the combination of SFINAE and the BCCL using boost-concept-requires was quite difficult. I Just rechecked some things and I think this still is the case. I checked using a small source with things as "apple", "pear", "banana", so you'll see them in my answers.
[snipped] Even if you neded SFINAE, and if I'm not wrong enable_if can also be applied to structs. From enable_if docummentation " Enabling template class specializations Class template specializations can be enabled or disabled with enable_if. One extra template parameter needs to be added for the enabler expressions. This parameter has the default value void. For example: template <class T, class Enable = void> class A { ... };
template <class T> class A<T, typename enable_if<is_integral<T> >::type> { ... };
template <class T> class A<T, typename enable_if<is_float<T> >::type> { ... };"
That is indeed possible, just tried it with enable_if. But, technically speaking, I don't think this is SFINAE. I think it is partial specialization, and specialization is done here on enable_if<...>::type, finding matching candidates and if no one is found, using the unspecialized class. We don't have the real "Substitution Failure" here, where one or more overloads are discarded from the candidate set based on failing substitution. So these classes with enable_if work about the same way as tag dispatching does, though no tag is necessary. But also here I prefer tag dispatching because (my personal opinion) I find it resulting in more readable code.
*gives often compiler troubles and headaches: if a user makes an error somewhere, the compiler will not select any of the methods, and/or it will give completely incomprehensible error listings, just because of this SFINAE"
I thought that this was and advantage not a liability. The message is short: method not found. What errors do you get when a user makes an error somewhere with tag dispatching? Are they clearer?
The messages you get depend on the type or error, in both cases. When I try to use a function based on sfinae, when there is no match, is: the message I get - from MSVC is: Failed to specialize function template..., for all overloads. - from gcc is: no matching function for call to.... (one) On tag dispatching you'll get: MSVC: 'type' : is not a member of 'tag<T>' with [T=banana] gcc, similar or (if the banana-tag is implemented) MSVC: 'apply' : is not a member of 'dispatch<T>' with [T=tag<banana>::type] gcc: 'apply' is not a member of 'dispatch<banana_tag>' sfinae is based on overloads, and the problem I encountered with it (and with its messages) that in case of errors I often don't understand where the error originates from. I remember having to number several times all overloads (of e.g. "eat") to e.g. eat1, eat2, eat3, etc, to see what is actually going wrong and why the overload was not called in that specific case. With tag dispatching you can also get pages of messages, but it is more clear where they come from, e.g. a missing specialization, a wrong input type.
* does not support partial specializations because it is a function. The tag-dispatching function is of course also not supporting that, but it forwards its call to the dispatch struct where partial specializations (and member template functions) are possible. The SFINAE could do that as well but then: why not just add one tag more and have tag dispatching instead?"
Could you clarify which is the tag you add?
If I understand your question: we're adding a geometry-tag. So for a point it specializes to point_tag, etc. What is meant by this section is that for some cases, code is similar. For example the "num_points" algorithm, the number of points of a linestring is the same as the number of points of a linear ring. The dispatch function can specialize partially on this similarity. I now realize, by just doing some re-checking that for SFINAE you can do the same, using SFINAE on a specific property to define an overload which applies to more than one geometry. So this sentence probably can go, it is possible in both cases.
* is a trick to deceive the compiler. "As a language behavior it was designed to avoid programs becoming ill-formed" (http://en.wikipedia.org/wiki/Substitution_failure_is_not_an_error), while tag dispatching is based on specialization, a core feature of C++ * looks more ugly
You know that this is a matter of taste, and the way you do force the user to share your taste.
I can rephrase this. What I mean is that a function template <typename T> void eat(T const& fruit) { // tag dispatch on apple-tag } looks better than: template <typename T> void eat(T const& fruit #ifdef DOXYGEN_SHOULD_SKIP_THIS , typename boost::enable_if<typename is_apple<T>::type>::type* = NULL #endif ) { // (call) apple implementation } Maybe I should state "makes the main free function declarations shorter" to be more objective.
*is simply not necessary because we have tag dispatching :-)
Not necessary do not meens that it is not good.
Right, I agree. I still find (but that is an opinion indeed) that using tag dispatching results in clean and readable code, and cause less compiler troubles. Besides that, as far as I can tell, in combination with BOOST_CONCEPT_REQUIRES, a solution based on SFINAE alone is not possible using SFINAE. This set does not compile: template <typename T> BOOST_CONCEPT_REQUIRES( ((concept::Apple<T> )), (void) ) eat(T const& fruit, typename boost::enable_if<typename is_apple<T>::type>::type* = NULL) {...} template <typename T> BOOST_CONCEPT_REQUIRES( ((concept::Pear<T> )), (void) ) eat(T const& fruit, typename boost::enable_if<typename is_pear<T>::type>::type* = NULL) {...} With messages: 'sourness' : is not a member of 'pear' or in gcc: no type named 'sourness' in struct pear But the expected type "sourness" was defined for apple, in this case, and checked by the apple concept... the code IS right.... Combinations are listed in the errors (so apple/pear, pear/apple), if we add more fruit we would get much more. Using tag dispatching, it is not possible to phrase it like this, because there is only one free function, we cannot check the Apple concept here. But concepts can be dispatched as well, resulting in: template <typename T> BOOST_CONCEPT_REQUIRES( (( dispatched_concept<typename tag<T>::type, T> )), (void) ) eat(T const& fruit) {...} and this compiles. Tag dispatching of the concept, or a solution using enable_if in a struct, can also be used in the SFINAE solution but... then it is not pure SFINAE (if I'm right), it is (at least partly) based on tag dispatching or other partial specializations. But OK, you can combine SFINAE and tags, of course that is possible. By the way, we're currently using BOOST_CONCEPT_ASSERT (where concept checking is dispatched), but as found out here, we have the choice
[snipped] Do you think that this could be also applied to the GGL library at least for the concepts?
Interesting, I'll react on the convert_to in another e-mail later. Regards, Barend