c++ 提供与参数类型相同的模板类型会导致右值引用函数出错

ckocjqey  于 2023-02-17  发布在  其他
关注(0)|答案(1)|浏览(146)

我使用了一个带有模板函数的库,该函数接受一个右值引用,为了清楚起见,我显式地声明了模板类型,而不是依赖于推理。我注意到,当模板类型与参数类型相匹配,并且参数是一个左值时,我得到了一个编译器错误。请参见下面的示例,其中错误在第三种情况下重现。

#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_ttypedef signed short int16_t
为什么会发生这种情况?我该如何解决它?为了安全起见,我希望继续明确使用模板类型。

5n0oy7gb

5n0oy7gb1#

根据您自己的实验,int16&&可以绑定到从int32左值转换而来的临时int16,但int32&&不能绑定到实际的int32左值。
这与模板无关,请参见下文:

void fnc16(int16_t&& value) {
  std::cout << value << std::endl;
}

void fnc32(int32_t&& value) {
  std::cout << value << std::endl;
}

int main() {
  int32_t var = 5;

  fnc16(var);  // OK

  fnc32(var);  // ERROR
}

https://godbolt.org/
这些规则看起来很奇怪。
例如,请注意,您可以通过创建一个右值来使其工作

fnc32(+var);  // OK now

通过为函数模板调用指定模板,而不是让它为你推导出来,很难理解你想要达到什么目的(推导是完全转发的工作原理)。
在任何情况下,如果您坚持要抑制扣减,则必须使用可以绑定到左值引用的正确模板类型,即:

fnc<int32_t&>(var);

在你的原始代码里。
这是因为引用塌陷:"int32_t& &&" -> int32_t&,这对于var是正确的(但现在对于+var是不正确的)。
事实上,任何限定参数都可能适用于<int32_t&><int32_t&&><int32_t const&>,但不适用于<int32_t>

相关问题