如何通过模板技术调用可存在的成员函数,我不想使用虚方法,因为该类是任意的。
例如:
class A {
void setValue(int value);
};
如何定义模板以调用类A
的setValue(如果存在),否则不执行任何操作。
模板类似于:
template <typename T>
struct call_if_exist {
void invokeOrNot(T& a, int value){ // EXISTING: setValue
a.setValue(value);
}
}
template <typename T>
struct call_if_exist {
void invokeOrNot(T& a, int value){ // NOT EXISTING: do nothing
}
}
这是关于调用,而不是检查。
答案 0 :(得分:1)
您可以利用SFINAE创建checks for the existence of a member function in a given class的类模板,并将结果用作布尔标志,以便在没有函数的情况下专门化您的模板,以及成员函数存在:
template<typename T , bool member_exists = has_set_value<T>::result>
struct call_if_exist;
template <typename T>
struct call_if_exist<T,true> {
void invokeOrNot(T& a, int value){ // EXISTING: setValue
a.setValue(value);
}
}
template <typename T>
struct call_if_exist<T,false> {
void invokeOrNot(T& a, int value){ // NOT EXISTING: do nothing
}
}
has_set_value
特征template<typename T>
class has_set_value
{
typedef struct{ char c[1]; } yes;
typedef struct{ char c[2]; } no;
template<typename U> static yes test(&U::set_value);
template<typename U> static no test(...);
public:
static const bool result = sizeof( test<T>(NULL) ) == sizeof( yes );
};
此类是SFINAE用于检查某个类的成员(类型或函数)是否存在的典型示例。
首先我们定义两个typedef,yes
和no
,用于通过sizeof
运算符区分重载决策。
test()
的第一个重载具有指向成员函数的指针作为参数,而最后一个是一个重载,其目标是由所有不是指向成员的指针调用即可。这是通过可变参数函数(注意省略号)完成的,它可以与任何类型的参数一起使用。
实现的重点是,即使第二个重载可以包含任何参数,第一个是指向我们的成员函数的指针的明确情况。所以如果参数可以是指向函数的指针,调用解析为第一个函数,否则解析为第二个函数。
正如我之前所说,我们使用typedef通过sizeof
运算符来区分重载决策:请注意,第一个重载返回yes
,后者返回no
。 因此,如果使用指针(NULL)调用test()
的结果类型的大小等于yes
的大小,则表示重载已解析为第一个,< strong>和作为参数传递的类(T
)有一个名为set_value
的成员函数。
Alexandrescu's Modern C++ Dessign在第二章check if one type is implicitly convertible to other中包含了这种特征的一个例子。