2012-07-31 123 views
14

已知模板参数可以是指向成员函数的指针。成员函数指针的模板参数推导

因此我可以这样写:

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; 

回答

5

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

#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或类似的编译器扩展。重写更安全的版本需要模拟可变模板。了解。

+0

其实,我使用丑陋的宏(这是一个库内部的模板,所以没有被误用的真正风险)。无论如何,'member_ptr_traits'非常棒,因为我实际上需要'T'类型。 – rodrigo 2012-07-31 19:38:04

7

答案很简单:没有没有。

问题是,要使typedef Foo<&Bar::fun> FooBar;正常工作,模板必须具有单个非类型参数,但在声明模板时该参数的类型将是未知的,这是无效的。另一方面,类型演绎从不应用于模板的参数(仅适用于函数模板的参数,但这些参数是函数的参数,而不是模板)。

+0

了解。所以也不可能做一个模板函数,不是吗? – rodrigo 2012-07-31 19:35:22

+0

@rodrigo:如果您想将该模板参数作为指向成员的是。问题是你是否需要指向成员的指针作为模板参数,或者它可以是函数参数,可以推导出来。 – 2012-07-31 21:03:56

+0

是的,我需要它是一个模板参数,因为它必须用于实例化一个嵌套模板。无论如何,感谢您的洞察 – rodrigo 2012-07-31 21:48:36