将成员函数指针作为参数传递给模板方法
Passing a member function pointer as an argument to a template method
我正在尝试编写一个接受成员函数指针作为参数的模板化方法。
这里有一个例子class,包括我最近尝试写的模板方法:
class MyClass
{
public:
int myMethod() { return 1; }
template<typename T>
T call(std::function<T(MyClass*)> m)
{
return m(this);
}
};
我的目标是能够执行以下操作(或语法上非常相似的操作):
MyClass m;
auto result = m.call(&MyClass::myMethod);
到目前为止,通过我上面的尝试,我可以做到:
MyClass m;
std::function<int(MyClass*)> f = &MyClass::myMethod;
auto result = m.call(f);
令我惊讶的是,我什至无法将其包装成一行。 m.call(&MyClass::myMethod)
这不编译。为什么?
我确信有一种方法可以获得我想要的行为,因此非常感谢任何帮助!
显然它无法推导 T
(来自非常推导的 ctor 参数的模板参数)。
如果您的目标只是在一次调用中完成,您可以将方法定义更改为类似
template<class F> auto call(F &&f) {
return std::invoke(std::forward<F>(f), this);
}
I was surprised I was not even able to wrap that into a single line.
m.call(&MyClass::myMethod)
... this does not compile. Why?
成员函数指针具有以下类型
<return-type>(ClassType::*)(<args>)<specifiers-if-any>
意思是&MyClass::myMethod
有类型
int(MyClass::*)(void)
这不等于 std::function<int(MyClass*)>
类型,编译器无法直接推导它,因此出现编译错误。
但是,如果我们显式只提及模板类型,则可以推导出std::function<int(MyClass*)>
,与some type erasur overheads。这意味着您可以像下面这样明确提及模板参数:
/* const */ int result = m.call<int>(&MyClass::myMethod); // works!
// ^^^^^^ -> mention T == int here!
I'm sure there's a way to get the behaviour[...]
如果您不使用 std::function
而是正常的(模板化的)成员函数指针类型,这将起作用。
template<typename T>
T call(T(MyClass::* m)())
{
return (this->*m)();
// or
// std::invoke(m, this); // in C++17
}
现在你可以
/* const */ int result = m.call(&MyClass::myMethod);
如果语法令人困惑,您可以像这样为成员函数指针提供一个模板类型别名。
class MyClass
{
// template type alias
template<typename T> using MemFunctionPtrT = T(MyClass::*)();
public:
// other codes
template<typename T>
T call(MemFunctionPtrT<T> m) // use the alias type like
{
return (this->*m)();
// or
// std::invoke(m, this); // in C++17
}
};
我正在尝试编写一个接受成员函数指针作为参数的模板化方法。
这里有一个例子class,包括我最近尝试写的模板方法:
class MyClass
{
public:
int myMethod() { return 1; }
template<typename T>
T call(std::function<T(MyClass*)> m)
{
return m(this);
}
};
我的目标是能够执行以下操作(或语法上非常相似的操作):
MyClass m;
auto result = m.call(&MyClass::myMethod);
到目前为止,通过我上面的尝试,我可以做到:
MyClass m;
std::function<int(MyClass*)> f = &MyClass::myMethod;
auto result = m.call(f);
令我惊讶的是,我什至无法将其包装成一行。 m.call(&MyClass::myMethod)
这不编译。为什么?
我确信有一种方法可以获得我想要的行为,因此非常感谢任何帮助!
显然它无法推导 T
(来自非常推导的 ctor 参数的模板参数)。
如果您的目标只是在一次调用中完成,您可以将方法定义更改为类似
template<class F> auto call(F &&f) {
return std::invoke(std::forward<F>(f), this);
}
I was surprised I was not even able to wrap that into a single line.
m.call(&MyClass::myMethod)
... this does not compile. Why?
成员函数指针具有以下类型
<return-type>(ClassType::*)(<args>)<specifiers-if-any>
意思是&MyClass::myMethod
有类型
int(MyClass::*)(void)
这不等于 std::function<int(MyClass*)>
类型,编译器无法直接推导它,因此出现编译错误。
但是,如果我们显式只提及模板类型,则可以推导出std::function<int(MyClass*)>
,与some type erasur overheads。这意味着您可以像下面这样明确提及模板参数:
/* const */ int result = m.call<int>(&MyClass::myMethod); // works!
// ^^^^^^ -> mention T == int here!
I'm sure there's a way to get the behaviour[...]
如果您不使用 std::function
而是正常的(模板化的)成员函数指针类型,这将起作用。
template<typename T>
T call(T(MyClass::* m)())
{
return (this->*m)();
// or
// std::invoke(m, this); // in C++17
}
现在你可以
/* const */ int result = m.call(&MyClass::myMethod);
如果语法令人困惑,您可以像这样为成员函数指针提供一个模板类型别名。
class MyClass
{
// template type alias
template<typename T> using MemFunctionPtrT = T(MyClass::*)();
public:
// other codes
template<typename T>
T call(MemFunctionPtrT<T> m) // use the alias type like
{
return (this->*m)();
// or
// std::invoke(m, this); // in C++17
}
};