EDIT : completed and fixed.
Another approach that uses ambiguity in inheritance is probably functionally equivalent to your approach 2. I remember that I have problems with approach 1 (it compiles with g ++ 4.4.5), because name resolution caused an error, not a replacement failure. I had to resort to:
template <class T> struct has_foo { struct fallback { void foo(...); }; struct D : T, fallback { }; template <typename U, U> struct K;
This works when T is a class, so you can add your own layer to check if T is a class type.
Note that any member function foo will be detected. If you want to check whether the detected function foo can be called with the given arguments, you must make another SFINAE layer:
// Check whether foo can be called with an argument of type Arg // and yields an element of type Res. // If you need Res = void, this code does not work. template <class T, typename Arg, typename Res> struct check_foo { struct flag {}; struct D : T { using T::foo; flag foo(...); }; template <typename U> static char (&test(U))[1]; template <typename> static char (&test(...))[2]; static Arg f(); static const bool value = sizeof(test<Arg>( ((D*)0)->foo(f()) )) == 1; };
Alexandre C.
source share