|
Boost : |
From: Simonson, Lucanus J (lucanus.j.simonson_at_[hidden])
Date: 2008-07-22 17:33:00
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
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk