
Bruno wrote:
So I deduce that, more generally, a compiler compiles the return type of every candidate overload before selecting the right one, and that's why we have this issue with concept checking. So I have 2 questions: - would there be any way to differ the check until after the right overload has been selected, thus doing the check only for that overload? - if no, is there a better workaround than replacing BOOST_CONCEPT_REQUIRES by a simple BOOST_ASSERT inside the function?
I ran into a problem with the flexibility of SFNAE where indirection in the substitution failure resulted in an error. template <typename T> struct metafunction { typedef typename T::some_type type; }; struct A {}; //A does not define some_type template <typename T> metafunction<A>::type foo(T t) {} //intended SFNAE protected function template <typename T> void foo(T t) {} int main() { foo(A()); return 0; }
gcc/4.3.0/g++ -g -Wall test8.cpp test8.cpp: In instantiation of ?metafunction<A>?: test8.cpp:8: instantiated from here test8.cpp:3: error: no type named ?some_type? in ?struct A?
And from this behavior of the compiler I inferred that substitution failure is not an error only in a direct sense. It succeeded in substituting A in metafunction because metafunction defines type for all T, but because A doesn't define some_type it is a syntax error, not substitution failure at that point in compilation. This seems to be similar to what you wrote and the problem you saw. I work around the issue in my library by making structs that I intended to use for SFNAE empty by default and specialize them for each type. It would be convenient if BOOST_CONCEPT_REQUIRES somehow worked around this limitation and allowed me to specify a default expectation for a type that can substitute in a metafunction so that only those that don't model the concept as expected need a concept mapping specialization of the metafunction and still provide SFNAE behavior. I don't know if that is possible. Right now I have a generic concept that encompasses all geometric types: template <typename T> struct geometry_concept {}; This is a metafunction which I use to lookup the conceptual type of a given type and I specialize it for each data type like so: template <> struct geometry_concept<int> { typedef coordinate_concept type; }; template <typename T> struct geometry_concept<rectangle_data<T> > { typedef rectangle_concept type; }; This registers each type with the library so I know what to do with it. By doing it this way I am able to use the geometry_concept metafunction for SFNAE, but if the default looks like: template <typename T> struct geometry_concept { typedef typename T::concept_type type; } the compiler then gives me syntax errors instead of SFNAE behavior. I would prefer not to have to register types that implement the default expectation for their behavior, but couldn't see a way around it. It looks like the concept check is able to give you a syntax error in the case that the given type doesn't model the concept, but it does not also provide SFNAE to allow you to define another generic function of the same name to handle such a type. Whether that is a compiler bug or not, I don't know, but we need to write code that works with the current generation of compilers. Bruno's problem still isn't solved. He can get SFNAE by making DummyConcept empty by default and specialize it for each type that models the concept, but that isn't really satisfactory. In my case, my expectation for user types is that they will always require a concept map because I assume they were authored prior to my library, so for me requiring registration and concept mapping specializations of traits classes is not an undue burden. Particularly since specializations can themselves be templates, and can even inherit from other specializations, providing the required specializations is minimal effort. BTW, I have finished the complete design and implementation for generic operator syntax for Boolean geometric operations in my library, and if there is interest I'd be happy the share the design with the list. I allow syntax such as: std::vector<RectangleType> rects1, rects2, rects3; rects1 & rects2 & rects3; Where operator& is (SFNAE safely) generic and implements a boolean AND operation on the 2D geometry of the arguments with operator templates. The requirement is that the types used be registered with the library and have the appropriate traits defined. Currently I have a 30 page powerpoint document that describes the API design and implementation. It is text only with lots of code examples, so I could make it into one very long email and send it to the boost list for feedback. The up-to-date code is also checked into the sandbox under gtl. It compiles under gcc 3.2.2 3.4.2, 4.2.0 and 4.3.0 as well as recent icc versions. I have not yet tried it on windows. Luke