C++ 使用SFINAE处理GCC而不是Clang的代码

C++ 使用SFINAE处理GCC而不是Clang的代码,c++,c++11,g++,sfinae,clang++,C++,C++11,G++,Sfinae,Clang++,我试图在C++11中使用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, typena

我试图在C++11中使用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;
}
模板
constexpr auto有\u save \u方法(A&ar,T&T)->decltype(T.save(ar),bool()){
返回true;
}
模板
结构保存器;
模板
结构保护程序{
静态空隙应用(A&R、T&T){
t、 储蓄(ar);
}
};
类MyClass{
公众:
模板
作废保存(应收和应付){
//将实例保存到存档中
}
};
类MyArchive{};
模板
作废保存到存档(应收、应付和应付){
saver::应用(ar,t);
}
int main(int argc,字符**argv){
MyClass x;
我的档案a;
将_保存到_存档(a,x);
返回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);
         ^
test.cpp:30:28:错误:非类型模板参数不是常量表达式
saver::应用(ar,t);
^ 
test.cpp:36:2:注意:在函数模板专门化的实例化中
此处请求“保存到存档”
将_保存到_存档(a,x);
^

发生了什么以及如何使它与这两个编译器一起工作?

正如所讨论的,这看起来是一个棘手的问题

另一种解决方法是使用
void\t技巧

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;
};
模板
使用void\u t=void;
模板
结构具有保存方法{
constexpr静态布尔值=false;
};
模板
结构具有保存方法{
constexpr静态布尔值=真;
};
然后像这样使用它:

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);
}
模板
作废保存到存档(应收、应付和应付){
saver::应用(ar,t);
}

我对C++11太缺乏经验,无法理解问题本身,但您的解决方案有效;谢谢