关于这个问题,这可能是过于简单化了,我在这里给出一个更复杂的例子。我假定的问题用以下代码描述:
// test3.cpp
using namespace std;
template<typename T>
struct exer
{
template<typename R, typename... rArgs, typename... pArgs>
R operator()(R(T::*f)(rArgs...), pArgs&&... args)
{
return (t.*f)(forward<pArgs>(args)...);
}
T t;
};
struct A
{
int addition() { return 0; }
template<typename... Args>
int addition(int a, Args... args) { return a + addition(args...); }
};
struct B
{
public:
template<typename... Args>
int addition(Args&&... args)
{
return m_e(&A::addition, forward<Args>(args)...);
}
private:
exer<A> m_e;
};
int main()
{
B b;
cout << b.addition(1, 2, 3, 4) << endl;
}
这里的问题是,在B::addition
的实例化中,&A::addition
的类型是未知的,因为存在不同的过载。此外,B::addition
也不知道必须使用哪个过载。直到函数被调用,它才知道编译器。但是,为了正确指定在exer<A>::operator()
中必须使用哪个过载,我需要对&A::addition
进行强制转换,以将其强制转换为正确的过载。
如何提取目标函数的正确重载类型?
更改问题。如果您可以使exer
接受一个可调用对象,而不是一个指向成员函数的指针,如下所示:
template<typename T>
struct exer
{
T t;
template<typename F, typename... pArgs>
auto operator()(F f, pArgs&&... args)
-> decltype(f(t, forward<pArgs>(args)...))
{
return f(t, forward<pArgs>(args)...);
}
};
那么你可以这样做:
struct B
{
public:
template<typename... Args>
int addition(Args&&... args)
{
struct Invoker {
auto operator()(A& a, Args&&... args) const
->decltype(a.addition(std::forward<Args>(args)...))
{ return a.addition(std::forward<Args>(args)...); }
};
return m_e(Invoker(), forward<Args>(args)...);
}
private:
exer<A> m_e;
};
现在选择正确的A::addition
是由编译器使用正常的重载解析规则完成的。
可以使用lambda表达式代替Invoker
,这样可以减少一些重复:
return m_e( [](A& a, Args&&... as) {
return a.addition(forward<Args>(as)...);
},
forward<Args>(args)...);