具有可变模板的SFINAE
SFINAE with variadic templates
本文关键字:SFINAE 更新时间:2023-10-16
我对模板编程有点陌生,所以这可能是一个愚蠢的问题。我试图使用可变模板来检查类是否有成员(称为member
)。为此,我编写了这个类has_member
。
#include <iostream>
using namespace std;
class ClassWithMember
{
public:
int member;
};
class ClassWithoutMember
{
};
template <typename T>
class has_member
{
template <typename... C>
class tester: public std::false_type
{
};
template <typename First>
class tester<First>: public std::true_type
{
void tester_fn(decltype(First::member));
};
public:
enum { value = tester<T>::value };
};
template<typename T1>
void my_function(const std::enable_if_t<has_member<T1>::value, T1> &obj)
{
cout<<"Function for classes with member"<<endl;
}
template<typename T1>
void my_function(const std::enable_if_t<!has_member<T1>::value, T1> &obj)
{
cout<<"Function for classes without member"<<endl;
}
int main()
{
ClassWithMember objWithMember;
ClassWithoutMember objWithoutMember;
my_function<ClassWithMember> (objWithMember);
my_function<ClassWithoutMember> (objWithoutMember);
}
我期望通过SFINAE,用不带成员的类替换特化模板会无声地失败,并回落到通用模板。但是我得到了错误:
trial.cpp: In instantiation of ‘class has_member<ClassWithoutMember>::tester<ClassWithoutMember>’:
trial.cpp:28:10: required from ‘class has_member<ClassWithoutMember>’
trial.cpp:38:41: required by substitution of ‘template<class T1> void my_function(std::enable_if_t<(! has_member<T1>::value), T1>&) [with T1 = ClassWithoutMember]’
trial.cpp:49:54: required from here
trial.cpp:24:14: error: ‘member’ is not a member of ‘ClassWithoutMember’
void tester_fn(decltype(First::member));
SFINAE仅适用于直接上下文替换。之外的替换失败是错误。这就是你遇到的问题:
has_member<ClassWithoutMember>::value // error
这是因为替换失败不是发生在has_member
或tester
的声明中,而是发生在定义中。那太晚了。你得把它推得更早。您可以使用void_t
将其推入has_member
的专门化:
template <typename... T>
struct make_void { using type = void; };
template <typename... T>
using void_t = typename make_void<T...>::type;
template <typename T, typename = void>
struct has_member : std::false_type { };
template <typename T>
struct has_member<T, void_t<decltype(T::member)>> : std::true_type { };
现在,如果没有T::member
,在尝试选择has_member
的正确专门化时,替换失败将发生在替换的直接上下文中。替换失败是而不是错误,特定的专门化将被丢弃,我们最终得到false_type
。
作为旁注,您使用enable_if_t
的方式可以防止模板演绎。你应该这样写:
template <typename T1,
std::enable_if_t<has_member<T1>::value>* = nullptr>
void my_function(const T1& obj) { ... }
template <typename T1,
std::enable_if_t<!has_member<T1>::value>* = nullptr>
void my_function(const T1& obj) { ... }
你可以这样写:
my_function(objWithMember);
my_function(objWithoutMember);
相关文章:
- 为什么使用SFINAE而不是函数重载
- 如何使用模板函数的函数签名进行SFINAE
- 数据成员SFINAE的C++17测试:gcc vs clang
- 使用在用于SFINAE的void_t中具有参数的方法
- 编译器如何在使用SFINAE的函数和标准函数之间确定两者是否可行
- 提供与TMP和SFINAE的通用接口
- "Inverse SFINAE"避免模棱两可的过载
- 表达式 SFINAE:如何根据类型是否包含具有一个或多个参数的函数来选择模板版本
- 如何在儿童类中使用SFINAE
- 使用 SFINAE 作为模板参数的编译时递归
- 使用 SFINAE 设计模板方法
- 与SFINAE支票交朋友
- C++许多 SFINAE 风格的过载
- 是否可以混合使用SFINAE和模板专业化?
- C++表达SFINAE和ostream操纵器
- SFINAE不能防止模棱两可的操作员过载吗?
- SFINAE是否取决于类型推断?
- MSVC 无法编译 SFINAE 检查
- SFINAE 检查模板参数运算符
- SFINAE 与 numeric_limits<T>::max() 在 MSVC2017 上