我使用了一个带有模板函数的库,该函数接受一个右值引用,为了清楚起见,我显式地声明了模板类型,而不是依赖于推理。我注意到,当模板类型与参数类型相匹配,并且参数是一个左值时,我得到了一个编译器错误。请参见下面的示例,其中错误在第三种情况下重现。
#include <cstdlib>
#include <iostream>
template <class T>
void fnc(T &&value) {
std::cout << value << std::endl;
}
int main() {
int32_t var = 5;
// Call with no template type and lvalue: OK
fnc(var);
// Call with different template type and lvalue: OK
fnc<int16_t>(var);
// Call with same template type and lvalue: ERROR
// cannot bind rvalue reference of type ‘int&&’ to lvalue of type ‘int32_t’ {aka ‘int’}
fnc<int32_t>(var);
// Call with no template type and rvalue: OK
fnc(5);
// Call with different template type and rvalue: OK
fnc<int16_t>(5);
// Call with same template type and rvalue: OK
fnc<int32_t>(5);
return 0;
}
注意,在我的机器上,cstdlib
引入了typedef signed int int32_t
和typedef signed short int16_t
。
为什么会发生这种情况?我该如何解决它?为了安全起见,我希望继续明确使用模板类型。
1条答案
按热度按时间5n0oy7gb1#
根据您自己的实验,
int16&&
可以绑定到从int32
左值转换而来的临时int16
,但int32&&
不能绑定到实际的int32
左值。这与模板无关,请参见下文:
https://godbolt.org/
这些规则看起来很奇怪。
例如,请注意,您可以通过创建一个右值来使其工作
通过为函数模板调用指定模板,而不是让它为你推导出来,很难理解你想要达到什么目的(推导是完全转发的工作原理)。
在任何情况下,如果您坚持要抑制扣减,则必须使用可以绑定到左值引用的正确模板类型,即:
在你的原始代码里。
这是因为引用塌陷:
"int32_t& &&" -> int32_t&
,这对于var
是正确的(但现在对于+var
是不正确的)。事实上,任何限定参数都可能适用于
<int32_t&>
、<int32_t&&>
、<int32_t const&>
,但不适用于<int32_t>
。