函数参数模板参数对于const ref类型不明确

Lao*_*Lao 2 c++ templates c++11 forwarding-reference

我有一个问题将const ref参数传递给调用其他函数的模板函数.请考虑以下代码:

struct A
{
    void foo(const int& i) { }
};

template <class ...Args> 
void a_caller(A& a, void(A::*f)(Args...), Args&& ...args)
{
    (a.*f)(std::forward<Args>(args)...);
}

int main()
{
    int i = 42;
    A a;

    a_caller(a, &A::foo, i); // (1) compiler error
    a_caller<const int&>(a, &A::foo, i); // (2) ok
}
Run Code Online (Sandbox Code Playgroud)

所以,我有一个成员函数A::fooconst int&我想在包装器中调用的参数a_caller.第(1)行导致以下错误:

'void a_caller(A &,void (__thiscall A::* )(Args...),Args &&...)' : template parameter 'Args' is ambiguous
see declaration of 'a_caller'
could be 'const int&'
or       'int&'
Run Code Online (Sandbox Code Playgroud)

我的第一个问题是为什么会这样?我给编译器一个非重载函数A :: foo,为什么不能Args从它推导出来呢?第二个问题是为什么std :: make_unique不会发生这种情况呢?以下代码对我来说是相同的,但编译器在推导构造函数参数类型方面没有问题:

struct A
{
    A(const int& i)  { }
};

int main()
{
    int i = 42;
    auto aptr = std::make_unique<A>(i);
}
Run Code Online (Sandbox Code Playgroud)

Rei*_*ica 6

你正在努力Args实现两种截然不同(并不一定兼容)的角色.第一个角色是参数的类型f.第二个是给出的参数类型a_caller.

因为完美转发的实现方式,通过i在你的例子要推断Args类型此i作为int &.但是,相同的Args类型A::foo是类型const int &- 因为模糊推论.

在某种程度上,完美转发的整个要点是转发参数的类型是在现场推断出来的(并且通常不能用于其他任何东西).所以你必须做这样的事情:

template <class ...Params, class ...Args>
void a_caller(A& a, void(A::*f)(Params...), Args&& ...args)
{
  (a.*f)(std::forward<Args>(args)...);
}
Run Code Online (Sandbox Code Playgroud)

f当参数与参数不匹配时,您将不得不依赖于告诉您的调用.