mardi 30 juin 2015

Is this SFINAE technique involving variadic templates valid? [duplicate]

libstdc++'s implementation of std::experimental::optional uses a SFINAE technique that seems to work with gcc, but not with clang.

I've reduced it to the following minimal example:

// Standard enable_if class
template <bool> struct enable_if {};
template <> struct enable_if<true> { typedef int type; };

// An example trait
template <typename> struct trait { static const bool value = true; };

// Overload to call if the trait is false
template<typename T, typename enable_if<!trait<T>::value>::type...>
void foo(T);

// Overload to call if the trait is true
template<typename T, typename enable_if<trait<T>::value>::type...>
void foo(T);

// Call site
void bar() {
    foo(0);
}

This compiles with gcc, but not with clang. Clang's error is:

test.cpp:18:5: error: call to 'foo' is ambiguous
    foo(0);
    ^~~
test.cpp:11:6: note: candidate function [with T = int, $1 = <>]
void foo(T);
     ^
test.cpp:14:6: note: candidate function [with T = int, $1 = <>]
void foo(T);
     ^

Clearly, gcc is discarding the first overload as a candidate because it encounters a substitution failure while subtituting T = int into typename enable_if<!trait<T>::value>::type.

Clang, on the other hand, seems to skip performing that substitution, perhaps because it realizes that there are zero template arguments bound to that parameter pack. As a result, it doesn't encounter a substitution failure, and the first overload remains viable.

Who is right?

Aucun commentaire:

Enregistrer un commentaire