将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
}
所以,我有一个带有A::foo
参数的成员函数const 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&'
我的第一个问题是为什么会这样?我给编译器一个非重载函数A :: foo,为什么它不能从中推导出Args
?
第二个问题是为什么std :: make_unique不会发生这种情况呢?以下代码对我来说是相同的,但编译器在推导构造函数参数类型方面没有问题:
struct A
{
A(const int& i) { }
};
int main()
{
int i = 42;
auto aptr = std::make_unique<A>(i);
}
答案 0 :(得分:6)
你正试图将Args
变成一个角色,以履行两个截然不同(并不一定兼容)的角色。第一个角色是f
的参数类型。第二种是给a_caller
的参数类型。
由于实现了完美转发的方式,因此在示例中传递i
想要将此Args
的{{1}}类型推断为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)...);
}
当参数与参数不匹配时,您必须依赖f
的调用来告诉您。
答案 1 :(得分:1)
错误消息告诉您发生了什么
<div>
<div class="text_wrapper">
<span class="text_overflow">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce malesuada feugiat odio rhoncus dapibus.</span>
</div>
</div>
.text_wrapper{
width: 100px;
white-space: nowrap;
overflow: hidden;
}
.text_overflow {
word-wrap: none;
}
所以你传递的成员函数需要see declaration of 'a_caller'
could be 'const int&'
or 'int&'
,所以编译器将const int&
推导为Args
,但你也传递const int&
i
它推导为Args
。这些冲突让您收到错误。你可以const_cast
int&
编译或者你可以传递i
作为第二个参数
const int
答案 2 :(得分:1)
我的第一个问题是为什么会这样?我给编译器一个非重载函数A :: foo,为什么不能从中推导出Args?
因为你试图推断两次Args,对于函数a_caller的第一个和第二个参数。此推断的类型不匹配,第一个参数为==
,第二个参数为const int&
。
第二个问题是为什么std :: make_unique不会发生这种情况呢?
因为make_unique只是将其参数转发给类构造函数。
我认为您的代码应如下所示:
int&