通过模板调用可能不存在的成员函数

时间:2013-09-08 09:53:00

标签: c++ templates

如何通过模板技术调用可存在的成员函数,我不想使用虚方法,因为该类是任意的。

例如:

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
    }
}

这是关于调用,而不是检查。

1 个答案:

答案 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,yesno,用于通过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中包含了这种特征的一个例子。