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;
4

2 回答 2

7

简单的回答:不,没有。

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

于 2012-07-31T18:00:32.610 回答
6

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

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

于 2012-07-31T18:26:24.573 回答