如何获取成员函数指针的类?

时间:2015-01-23 07:36:33

标签: c++ c++11

考虑代码:

class Character
{
  void kill();
  void send_to_wall();
}

template <typename T>
void GeorgeFunc(T fp)
{
  ??? obj;
  (obj.*fp)();
}

int main()
{
  GeorgeFunc(&Character::kill);
}

所以我的问题是:我怎样才能获得????在模板实例化期间,似乎编译器肯定知道这个类型是什么(Character),但我不确定如何得到它。我目前的解决方法是更改​​为:void GeorgeFunc(void (T::*fp)()),但从成员函数指针中获取类型会更简洁。 decltype(fp)将返回void(Character::*)()decltype(fp())将返回void。获取Character的任何方式?

1 个答案:

答案 0 :(得分:13)

是的,只需使用特征来确定这一点。

template <typename> struct member_function_traits;

template <typename Return, typename Object, typename... Args>
struct member_function_traits<Return (Object::*)(Args...)>
{
    typedef Return return_type;
    typedef Object instance_type;
    typedef Object & instance_reference;

    // Can mess with Args... if you need to, for example:
    static constexpr size_t argument_count = sizeof...(Args);
};

// If you intend to support const member functions you need another specialization.
template <typename Return, typename Object, typename... Args>
struct member_function_traits<Return (Object::*)(Args...) const>
{
    typedef Return return_type;
    typedef Object instance_type;
    typedef Object const & instance_reference;

    // Can mess with Args... if you need to, for example:
    static constexpr size_t argument_count = sizeof...(Args);
};

现在您的声明是:

typename member_function_traits<T>::instance_type obj;

但是,我认为既然你需要一个成员函数指针(其他类型由于行(obj.*fp)() 1 而无法实例化),那么你的函数应该直接取成员函数指针而不是完全泛型类型。

所以这个定义不仅可以工作,而且我认为它更受欢迎 - 当有人使用除指针到成员函数之外的其他东西时,错误消息会更加清晰,因为参数类型将是不兼容的:

template <typename Return, typename Object>
void GeorgeFunc(Return (Object::*fp)())
{
    Object obj;
    (obj.*fp)();
}

请注意,这确实允许传递返回任何类型的指向成员的函数。由于我们并没有真正使用返回值,因此我们并不关心它是什么。没有理由像你的“解决方法”那样强制执行void

使用此方法的唯一缺点是,如果您还要接受指向const声明的成员函数的指针,则需要两次重载。完全通用的实现没有这个限制。 (我一直希望指向const成员函数的指针可以隐式转换为指向非const成员函数的指针,但目前C ++不允许这样做。)


1 这不是100%正确。如果您现在使用完全通用类型,那么调用者理论上可以传递成员 data 指针而不是成员 function 指针。 obj.*fp将评估为对数据成员的引用,然后您将在其上调用operator()()。只要数据成员的类型实现了此运算符,就可以实例化模板函数GeorgeFunc