2

假设我有一个类模板template <typename T> class X

是否有可能使用类型特征或类似技术来调用 T 的(静态)方法,但前提是类型 T 声明了这样的方法,例如:

template <typename T> 
class X {
    static void foo(){
       if(has_method(T,bar)) //Something like this      
         T::bar(); //If T has no bar() method, then foo does nothing
    }

};
4

2 回答 2

3
template <typename T>
class X {
public:
    static void foo() {
        foo_impl(static_cast<T*>(nullptr));
    }
private:
    // foo_impl #1
    template <typename U>
    static auto foo_impl(U*) -> decltype(U::bar(), void()) {
        U::bar();
    }

    // foo_impl #2
    static void foo_impl(...) {}
};

由于 SFINAE 规则, #1不是有效表达式foo_impl时不在重载集中,而是调用 #2。如果 #1 的类型推导确实成功,则它总是比省略号更好的转换。U::bar()foo_implfoo_impl

Ideone 演示:http: //ideone.com/UKVmIB

于 2013-02-04T15:31:29.823 回答
2

首先,您需要在编译时做出决定,否则,即使您从未进入分支,您也需要提供该函数。我可以想象这样的事情:

template <typename T, void (T::*)() > struct HasBar;

template <typename T>
void doBar( HasBar<&T::bar>* ) { T::bar(); }

template <typename T>
void doBar( ... ) {}

template <typename T>
class X
{
    static void f()
    {
        doBar<T>( 0 );
    }
};

这或多或少是一个经典的把戏。如果&T::bar失败(因为T没有成员bar),那么实例化doBar( HasBar<...>)失败,函数不加到重载集中,所以调用另一个。if&T::bar是一个合法的表达式,两个函数模板都可以成功实例化,并且在0匹配之前选择转换为指针...(这始终是确定函数重载决议时的最后手段)。

编辑:

我错过了函数是静态的这一事实。以上是针对非静态函数的。对于静态函数,将第一行更改为:

template <typename T, void (*)() struct HasBar;

其余的应该按原样工作。

于 2013-02-04T15:29:38.807 回答