简体   繁体   English

成员函数指针的模板参数推导

[英]Template argument deduction for member function pointers

It is known that template arguments can be pointers to member functions. 众所周知,模板参数可以是指向成员函数的指针。

So I can write: 所以我可以写:

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

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

typedef Foo<&Bar::fun> FooBar;

But what if I want the the Bar type itself to be a template argument: 但是如果我希望Bar类型本身成为模板参数呢?

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

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

Now, when I use it, I have to write Bar twice! 现在,当我使用它,我必须写Bar两次!

My question is: Is there a way to force the compiler to deduce the class type automatically? 我的问题是:有没有办法强制编译器自动推导出类类型?

The objective is for this to just work: 目标是让这个工作:

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

Simple answer: no there isn't. 简单的回答:没有。

The problem is that for typedef Foo<&Bar::fun> FooBar; 问题是对于typedef Foo<&Bar::fun> FooBar; to work, the template would have to have a single non-type argument, but the type of that argument would be unknown when the template is being declared, which is not valid. 要工作,模板必须有一个非类型参数,但是在声明模板时该参数的类型是未知的,这是无效的。 On the other side, type deduction is never applied to the arguments of the template (only to the arguments to function templates, but those are the arguments to the function, not the template). 另一方面,类型推导从不应用于模板的参数(仅适用于函数模板的参数,但这些是函数的参数,而不是模板的参数)。

You probably should just write the class name in there. 你可能应该只在那里写类名。 However, if you really want to avoid that you can use the evil magic of macros. 但是,如果你真的想避免它,你可以使用宏的邪恶魔法。 The simple version is more dangerous: 简单版本更危险:

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

This will accept any kind of non-type template parameter, and you may encounter hard-to-understand errors if the Foo implementation only works with pointers-to-member. 这将接受任何类型的非类型模板参数,如果Foo实现仅适用于指向成员的指针,则可能会遇到难以理解的错误。

To make it a bit safer you need a metafunction that tells you the class name: 为了使它更安全一点,你需要一个告诉你类名的元函数:

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

Also both of these use C++11 so they won't work with old compilers. 这两个都使用C ++ 11,因此它们不能与旧的编译器一起使用。 This simple version can be rewritten to use the old typeof or similar compiler extensions. 这个简单的版本可以改写使用旧typeof或类似的编译器扩展。 Rewriting the safer version requires simulating variadic templates. 重写更安全的版本需要模拟可变参数模板。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM