2016-07-19 5 views
2

シリアライゼーションライブラリを実装するためにC++ 11でSFINAEを使用しようとしています。私のコードはGCCでは正常に動作しますが、Clangではうまく動作しません。私はここで最小限のコードに減らしました:SFINAEを使用し、GCCで動作しますが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はこれをエラーなしでコンパイルします。何が起こっている

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); 
     ^

とどのように私はそれが両方のコンパイラで動作させることができます:クランは、しかし、私に次のようになりますか?

答えて

1

それを行うための議論HERE

別の解決策は、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; 
}; 

など、それを使用します。

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

私とあまりにも経験の浅いですよC++ 11では問題自体は理解できますが、ソリューションは機能します。ありがとう。 – sunmat

関連する問題