如何获取成员函数指针的class?
How can I get the class of a member function pointer?
考虑代码:
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)
会 return void(Character::*)()
,decltype(fp())
会 return void
。有什么方法可以得到 Character
?
是的,只是用一个特征来确定这个。
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)();
}
请注意,这确实允许传递 return 任何类型的指向成员函数的指针。因为我们并不真正使用 return 值,所以我们不关心它是什么。没有理由像您的 "workaround."
那样强制执行 void
使用此方法的唯一缺点是,如果您还打算接受指向已声明 const
的成员函数的指针,则需要两个重载。完全通用的实现没有这个限制。 (我一直希望指向 const
成员函数的指针可以隐式转换为指向非 const
成员函数的指针,但 C++ 目前不允许这样做。)
1 这并非 100% 正确。如果您像现在一样使用完全通用的类型,那么调用者理论上可以传递成员 data 指针而不是成员 function 指针。 obj.*fp
将评估为对数据成员的引用,然后您将对其调用 operator()()
。只要数据成员的类型实现了这个运算符,那么模板函数 GeorgeFunc
就可以被实例化。
考虑代码:
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)
会 return void(Character::*)()
,decltype(fp())
会 return void
。有什么方法可以得到 Character
?
是的,只是用一个特征来确定这个。
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)();
}
请注意,这确实允许传递 return 任何类型的指向成员函数的指针。因为我们并不真正使用 return 值,所以我们不关心它是什么。没有理由像您的 "workaround."
那样强制执行void
使用此方法的唯一缺点是,如果您还打算接受指向已声明 const
的成员函数的指针,则需要两个重载。完全通用的实现没有这个限制。 (我一直希望指向 const
成员函数的指针可以隐式转换为指向非 const
成员函数的指针,但 C++ 目前不允许这样做。)
1 这并非 100% 正确。如果您像现在一样使用完全通用的类型,那么调用者理论上可以传递成员 data 指针而不是成员 function 指针。 obj.*fp
将评估为对数据成员的引用,然后您将对其调用 operator()()
。只要数据成员的类型实现了这个运算符,那么模板函数 GeorgeFunc
就可以被实例化。