【问题标题】:Template argument deduction for member function pointers成员函数指针的模板参数推导
【发布时间】:2012-07-31 17:28:58
【问题描述】:

众所周知,模板参数可以是指向成员函数的指针。

所以我可以写:

struct Bar
{
    int fun(float x);
};

template <int (Bar::*FUN)(float)>
struct Foo
{ /*...*/ };

typedef Foo<&Bar::fun> FooBar;

但是,如果我希望 Bar 类型本身成为模板参数怎么办:

template <typename B, int (B::*FUN)(float)>
struct Foo
{ /*...*/ };

typedef Foo<Bar, &Bar::fun> FooBar;

现在,当我使用它时,我必须写两次Bar

我的问题是:有没有办法强制编译器自动推断类类型?

目标是让它正常工作:

typedef Foo<&Bar::fun> FooBar;
typedef Foo<&Moo::fun> FooMoo;

【问题讨论】:

    标签: c++ templates


    【解决方案1】:

    简单的回答:不,没有。

    问题在于,要使typedef Foo&lt;&amp;Bar::fun&gt; FooBar; 工作,模板必须有一个非类型参数,但在声明模板时该参数的类型是未知的,这是无效的。另一方面,类型推导永远不会应用于模板的参数(仅适用于函数模板的参数,但那些是函数的参数,而不是模板)。

    【讨论】:

    • 明白。所以模板函数也不可能这样做,不是吗?
    • @rodrigo:如果你想将该模板参数作为指向成员的指针,是的。问题是您是否需要指向成员的指针作为模板参数,或者它可以是函数参数,可以推导出来。
    • 是的,我需要它作为模板参数,因为它必须用于实例化嵌套模板。无论如何,谢谢你的洞察力
    【解决方案2】:

    你可能应该在里面写下类名。但是,如果你真的想避免这种情况,你可以使用宏的邪恶魔法。简单的版本更危险:

    #define TT(X) decltype(X), X
    
    template<typename T,T t>
    struct Foo
    { /* ... */ };
    
    struct Bar {
        int fun(float) {}
    };
    
    int main() {
        Foo<TT(&Bar::fun)> f;
    }
    

    这将接受任何类型的非类型模板参数,如果Foo 实现仅适用于指向成员的指针,您可能会遇到难以理解的错误。

    为了让它更安全一点,你需要一个告诉你类名的元函数:

    template<typename T> struct member_ptr_traits;
    
    template<typename Class,typename Ret,typename... Args>
    struct member_ptr_traits<Ret (Class::*)(Args...)>
    {
        typedef Class class_type;
        typedef Ret return_type;
    };
    
    #define TT(X) member_ptr_traits<decltype(X)>::class_type , X
    
    template<typename T,int (T::*FUN)(float)>
    struct Foo
    { /* ... */ };
    
    struct Bar {
        int fun(float) {}
    };
    
    int main() {
        Foo<TT(&Bar::fun)> f;
    }
    

    这两个都使用 C++11,所以它们不能与旧的编译器一起工作。这个简单的版本可以重写以使用旧的typeof 或类似的编译器扩展。重写更安全的版本需要模拟可变参数模板。

    【讨论】:

    • 实际上,我为此使用了丑陋的宏(它是库内部的模板,因此没有被滥用的真正风险)。无论如何,member_ptr_traits 很棒,因为我实际上需要 T 类型。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-17
    • 1970-01-01
    相关资源
    最近更新 更多