2016-07-19 25 views
2

Ich versuche SFINAE in C++ 11 zu verwenden, um eine Serialisierungsbibliothek zu implementieren. Mein Code funktioniert gut mit GCC, aber nicht mit Clang. Ich habe es hier zu einem minimalen Code reduziert:Code mit SFINAE arbeitet mit GCC aber nicht mit Clang

template <typename A, typename T> 
constexpr auto has_save_method(A& ar, T& t) -> decltype(t.save(ar), bool()) { 
     return true; 
} 

template<class A, typename T, bool has_save> 
struct saver; 

template<class A, typename T> 
struct saver<A,T,true> { 
     static void apply(A& ar, T& t) { 
       t.save(ar); 
     } 
}; 

class MyClass { 

     public: 

     template<typename A> 
     void save(A& ar) { 
       // Save the instance in the archive 
     } 
}; 

class MyArchive {}; 

template<typename A, typename T> 
void save_to_archive(A& ar, T& t) { 
     saver<A,T,has_save_method(ar,t)>::apply(ar,t); 
} 

int main(int argc, char** argv) { 
     MyClass x; 
     MyArchive a; 
     save_to_archive(a,x); 
     return 0; 
} 

GCC kompiliert das ohne Fehler. Clang jedoch gibt mir folgendes:

test.cpp:30:28: error: non-type template argument is not a constant expression 
     saver<A,T,has_save_method(ar,t)>::apply(ar,t); 
           ^
test.cpp:36:2: note: in instantiation of function template specialization 
     'save_to_archive<MyArchive, MyClass>' requested here 
     save_to_archive(a,x); 
     ^

Was passiert und wie kann ich es mit beiden Compiler funktioniert?

Antwort

1

Das sieht wie ein Clang Frage diskutiert, wie HERE

Eine andere Lösung, es zu tun ist mit void_t trick:

template <typename... T> 
using void_t = void; 

template <typename A, typename T, typename = void_t<>> 
struct has_save_method { 
    constexpr static bool value = false; 
}; 

template <typename A, typename T> 
struct has_save_method<A, T, void_t<decltype(std::declval<T&>().save(std::declval<A&>()))>> { 
    constexpr static bool value = true; 
}; 

Und es verwenden möchte:

template<typename A, typename T> 
void save_to_archive(A& ar, T& t) { 
     saver<A,T,has_save_method<A, T>::value>::apply(ar,t); 
} 
+0

Ich bin zu unerfahren mit C++ 11, um das Problem selbst zu verstehen, aber Ihre Lösung funktioniert; Vielen Dank. – sunmat