SPM*_*PMP 2 c++ templates c++11
我对模板编程有些新意,所以这可能是一个愚蠢的问题.我试图使用可变参数模板来检查一个类是否有一个成员(被调用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);
}
Run Code Online (Sandbox Code Playgroud)
我期待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));
Run Code Online (Sandbox Code Playgroud)
SFINAE仅适用于替代的直接背景.除此之外的替换失败是一个错误.这就是你遇到的问题:
has_member<ClassWithoutMember>::value // error
Run Code Online (Sandbox Code Playgroud)
那是因为替换失败不会在声明中发生,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 { };
Run Code Online (Sandbox Code Playgroud)
现在,如果没有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) { ... }
Run Code Online (Sandbox Code Playgroud)
那会让你写的:
my_function(objWithMember);
my_function(objWithoutMember);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
613 次 |
| 最近记录: |