如何通过模板技术调用可能存在的成员函数,我不想使用虚方法,因为类是任意的。
例如:
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
}
}
这是关于调用,而不是检查。
最佳答案
您可以利用 SFINAE制作一个类模板 checks for the existence of a member function in a given class ,并将结果用作 bool 标志,以针对没有函数的情况和成员函数存在的情况专门化您的模板:
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检查某个类的成员(类型或函数)是否存在的典型例子。
首先我们定义两个类型定义,yes
和 no
, 用于通过 sizeof
区分过载决议运营商。
test()
的第一次重载有一个指向成员函数的指针作为参数,最后一个是一个重载,目标是被所有不是指向成员的指针调用。这是通过可变参数函数(注意省略号)完成的,它可以与任何类型的参数一起使用。
实现的要点是即使第二个重载可以包含任何参数,第一个是指向我们成员函数的指针的显式情况。所以如果参数可以是指向函数的指针, 调用被解析为第一个函数,否则它被解析为第二个。
正如我之前所说,我们使用 typedef 通过 sizeof
来区分重载决议。运算符:请注意,第一个重载返回 yes
和后来的返回no
. 因此如果调用test()
的结果类型的大小使用指针 (NULL) 等于 yes
的大小, 意味着重载被解析为第一个,并且作为参数传递的类 ( T
) 有一个名为 set_value
的成员函数.
Alexandrescu's Modern C++ Dessign在 check if one type is implicitly convertible to other 的第二章中包含了此类特征的示例.
关于c++ - 通过模板调用可能不存在的成员函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18682409/