使用 SFINAE 检测模板方法
Dectecting template methods with SFINAE
我有一个简单的特性 struct hasMemberSerialize
,我试图用它来确定任何给定的 class 是否与 callSerialize()
兼容。 struct
看起来像这样:
template<typename Type, typename ArchiveType>
struct hasMemberSerialize {
template<typename T, typename A>
static auto test(int) -> decltype(Serialization::access::callSerialize(std::declval<A&>(), std::declval<T&>()), std::true_type);
template<typename, typename>
static std::false_type test(...);
static const bool value = std::is_same<decltype(test<Type, ArchiveType>(0)), std::true_type>::value;
};
编译并运行良好,但是,我的 hasMemberSerialize::value
是 always std::false_type
。我使用了类似的方法来检查非模板方法;但是,我正在检查的 callSerialize()
方法类似于:
template<typename Archive, typename Type>
static auto callSerialize(Archive& a, Type& t) -> decltype(t.serialize(a)) {
// Implementation
}
我用 std::cout
做了一些测试,像这样:
Serialization::access::callSerialize(JSON, myType);
std::cout << std::boolalpha
<< hasMemberSerialize<MyType, JSONOutputArchive>::value << std::endl;
方法调用 callSerialize(JSON, myType)
按预期工作并序列化类型;然而,hasMemberSerialize::value
打印 false
。最后,myType
是一个简单的测试 class:
class MyType {
int myInt;
public:
MyType() : myInt(4) {}
template<typename Archive>
void serialize(Archive& a) {
a(myInt);
}
};
...
MyType myType;
我犯了一个很简单的错误,行
static auto test(int) -> decltype(Serialization::access::callSerialize(std::declval<A&>(), std::declval<T&>()), std::true_type);
需要
static auto test(int) -> decltype(Serialization::access::callSerialize(std::declval<A&>(), std::declval<T&>()), std::true_type{});
注意:std::true_type
后的花括号.
正如 Max66 在他的评论中解释的那样:
the point is that decltype()
return the type of an object; so decltype(3)
is int
; when you write decltype(std::true_type)
(that is as decltype(int)
) you ask the type of a type; you have to ask the type of an object of type std::true_type
, that is decltype(std::true_type{})
or (better, IMHO) decltype(std::declval<std::true_type>())
正如您所发现的,问题在于您必须在 decltype()
的末尾使用 std::true_type{}
,并使用结束大括号
所以
decltype( <other elements>, std::true_type )
错了,报错,其中
decltype( <other elements>, std::true_type{} )
// .......................................^^
有效。
重点是decltype()
return给定实体(变量、常量等)的类型或该类型的表达式;所以(通过例子)给定 decltype(3)
,你得到 int
.
如果你写
decltype( std::true_type )
你问的是一个类型的类型,这是错误的。
如果你写
decltype( std::true_type{} )
您要求类型为 std::true_type
的元素 (std::true_type{}
) 的类型;这是正确的,你得到 std::true_type
.
我建议另一种方式:
decltype( std::declval<std::true_type>() )
其中 std::declval()
是一个标准模板函数(仅声明,但足以 decltype()
return 接收到模板类型的元素。
所以std::declval<std::true_type>()
是std::true_type
和decltype()
return类型的表达式,显然,std::true_type
.
对于默认可构造的类型,您可以创建该类型的实体,只需在类型名称的末尾添加几个大括号即可。但是当一个类型不是默认可构造的时,你无法解决这个原因。
使用 std::declval()
时,当该类型不是默认可构造的时,您也会得到给定类型的表达式。
在 std::true_type
的情况下,你可以用两种方式解决,但我建议无论如何都要使用 std::declval()
。
我有一个简单的特性 struct hasMemberSerialize
,我试图用它来确定任何给定的 class 是否与 callSerialize()
兼容。 struct
看起来像这样:
template<typename Type, typename ArchiveType>
struct hasMemberSerialize {
template<typename T, typename A>
static auto test(int) -> decltype(Serialization::access::callSerialize(std::declval<A&>(), std::declval<T&>()), std::true_type);
template<typename, typename>
static std::false_type test(...);
static const bool value = std::is_same<decltype(test<Type, ArchiveType>(0)), std::true_type>::value;
};
编译并运行良好,但是,我的 hasMemberSerialize::value
是 always std::false_type
。我使用了类似的方法来检查非模板方法;但是,我正在检查的 callSerialize()
方法类似于:
template<typename Archive, typename Type>
static auto callSerialize(Archive& a, Type& t) -> decltype(t.serialize(a)) {
// Implementation
}
我用 std::cout
做了一些测试,像这样:
Serialization::access::callSerialize(JSON, myType);
std::cout << std::boolalpha
<< hasMemberSerialize<MyType, JSONOutputArchive>::value << std::endl;
方法调用 callSerialize(JSON, myType)
按预期工作并序列化类型;然而,hasMemberSerialize::value
打印 false
。最后,myType
是一个简单的测试 class:
class MyType {
int myInt;
public:
MyType() : myInt(4) {}
template<typename Archive>
void serialize(Archive& a) {
a(myInt);
}
};
...
MyType myType;
我犯了一个很简单的错误,行
static auto test(int) -> decltype(Serialization::access::callSerialize(std::declval<A&>(), std::declval<T&>()), std::true_type);
需要
static auto test(int) -> decltype(Serialization::access::callSerialize(std::declval<A&>(), std::declval<T&>()), std::true_type{});
注意:std::true_type
后的花括号.
正如 Max66 在他的评论中解释的那样:
the point is that
decltype()
return the type of an object; sodecltype(3)
isint
; when you writedecltype(std::true_type)
(that is asdecltype(int)
) you ask the type of a type; you have to ask the type of an object of typestd::true_type
, that isdecltype(std::true_type{})
or (better, IMHO)decltype(std::declval<std::true_type>())
正如您所发现的,问题在于您必须在 decltype()
std::true_type{}
,并使用结束大括号
所以
decltype( <other elements>, std::true_type )
错了,报错,其中
decltype( <other elements>, std::true_type{} )
// .......................................^^
有效。
重点是decltype()
return给定实体(变量、常量等)的类型或该类型的表达式;所以(通过例子)给定 decltype(3)
,你得到 int
.
如果你写
decltype( std::true_type )
你问的是一个类型的类型,这是错误的。
如果你写
decltype( std::true_type{} )
您要求类型为 std::true_type
的元素 (std::true_type{}
) 的类型;这是正确的,你得到 std::true_type
.
我建议另一种方式:
decltype( std::declval<std::true_type>() )
其中 std::declval()
是一个标准模板函数(仅声明,但足以 decltype()
return 接收到模板类型的元素。
所以std::declval<std::true_type>()
是std::true_type
和decltype()
return类型的表达式,显然,std::true_type
.
对于默认可构造的类型,您可以创建该类型的实体,只需在类型名称的末尾添加几个大括号即可。但是当一个类型不是默认可构造的时,你无法解决这个原因。
使用 std::declval()
时,当该类型不是默认可构造的时,您也会得到给定类型的表达式。
在 std::true_type
的情况下,你可以用两种方式解决,但我建议无论如何都要使用 std::declval()
。