为什么 const double && 不适用于左值引用?
Why const double && doesn't work for lvalue reference?
请解释一下,它是如何工作的?
为什么 double && 适用于左值和右值?
为什么 const double && 不适用于左值?
template <typename U>
void function(U& var) {
std::cout << var << std::endl;
}
int main()
{
int var1 = 45;
function(var1);
function(45); //error
}
错误:从类型为“int”的右值函数对类型为“int&”的非常量引用的初始化无效(45);
////////////////////////////////////////////////////
template <typename U>
void function(const U& var) {
std::cout << var << std::endl;
}
int main()
{
int var1 = 45;
function(var1);
function(45);
}
////////////////////////////////////////// ///
template <typename U>
void function(U&& var) {
std::cout << var << std::endl;
}
int main()
{
int var1 = 45;
function(var1);
function(45);
}
////////////////////////////////////////// ///
template <typename U>
void function(const U&& var) {
std::cout << var << std::endl;
}
int main()
{
int var1 = 45;
function(var1); // error
function(45);
}
错误:无法将“int”左值绑定到“const int&&”函数(var1);
double &&
不适用于左值。但是,您的代码中没有 double &&
,推导的 U
有 U &&
。这是 so-called 转发引用的特殊语法。
C++模板推导规则中有一个特殊的规则,当参数类型为T&&
时,其中T
是推导类型,参数是[=16=类型的左值], 然后使用 X&
代替 X
进行类型推导。
在您的例子中,这意味着 U
被推断为 int&
,因此参数类型 var
从“int& &&
”折叠为 int &
.
您可以通过搜索 "forwarding reference"(历史上称为 "universal reference")或 "perfect forwarding."
等术语来了解有关此机制的更多信息
先总结一下规则。
- 左值可以绑定到 lvalue-reference
- 左值不能绑定到 rvalue-reference
- rvalues 可以绑定到 lvalue-reference 到 const
- 右值不能绑定到 lvalue-reference 到 non-const
- 右值可以绑定到 rvalue-reference
- 左值可以绑定到 forwarding-reference(并保留其值类别)
- 右值可以绑定到 forwarding-reference(并保留其值类别)
第一种情况是lvalue-reference到non-const,那么
function(var1); // rule#1 -> fine
function(45); // rule#4 -> fail
第二种情况是lvalue-reference转const,然后
function(var1); // rule#1 -> fine
function(45); // rule#3 -> fine
第3种情况是forwarding-reference,那么
function(var1); // rule#6 -> fine
function(45); // rule#7 -> fine
第4种情况是rvalue-reference,那么
function(var1); // rule#2 -> fail
function(45); // rule#5 -> fine
值得注意的是rvalue-reference和forwarding-reference的区别:
(强调我的)
function parameter of a function template declared as rvalue reference to cv-unqualified type template parameter of that same function template
在您的示例中,function(var1)
将推断 var1
用法为 lvalue
。要使其与 rvalue-based 模板兼容,您必须稍微帮助您的编译器:
template <typename U>
void function(const U&& var) {
std::cout << var << std::endl;
}
int main()
{
int var1 = 45;
function(std::move(var1)); // let convert lvalue to rvalue
function(45);
}
P.S。是的,你应该经常问自己 "do I really need that rvalue reference, or I'm perfectly fine with that old good lvalue ref?"
请解释一下,它是如何工作的? 为什么 double && 适用于左值和右值? 为什么 const double && 不适用于左值?
template <typename U>
void function(U& var) {
std::cout << var << std::endl;
}
int main()
{
int var1 = 45;
function(var1);
function(45); //error
}
错误:从类型为“int”的右值函数对类型为“int&”的非常量引用的初始化无效(45); ////////////////////////////////////////////////////
template <typename U>
void function(const U& var) {
std::cout << var << std::endl;
}
int main()
{
int var1 = 45;
function(var1);
function(45);
}
////////////////////////////////////////// ///
template <typename U>
void function(U&& var) {
std::cout << var << std::endl;
}
int main()
{
int var1 = 45;
function(var1);
function(45);
}
////////////////////////////////////////// ///
template <typename U>
void function(const U&& var) {
std::cout << var << std::endl;
}
int main()
{
int var1 = 45;
function(var1); // error
function(45);
}
错误:无法将“int”左值绑定到“const int&&”函数(var1);
double &&
不适用于左值。但是,您的代码中没有 double &&
,推导的 U
有 U &&
。这是 so-called 转发引用的特殊语法。
C++模板推导规则中有一个特殊的规则,当参数类型为T&&
时,其中T
是推导类型,参数是[=16=类型的左值], 然后使用 X&
代替 X
进行类型推导。
在您的例子中,这意味着 U
被推断为 int&
,因此参数类型 var
从“int& &&
”折叠为 int &
.
您可以通过搜索 "forwarding reference"(历史上称为 "universal reference")或 "perfect forwarding."
等术语来了解有关此机制的更多信息先总结一下规则。
- 左值可以绑定到 lvalue-reference
- 左值不能绑定到 rvalue-reference
- rvalues 可以绑定到 lvalue-reference 到 const
- 右值不能绑定到 lvalue-reference 到 non-const
- 右值可以绑定到 rvalue-reference
- 左值可以绑定到 forwarding-reference(并保留其值类别)
- 右值可以绑定到 forwarding-reference(并保留其值类别)
第一种情况是lvalue-reference到non-const,那么
function(var1); // rule#1 -> fine
function(45); // rule#4 -> fail
第二种情况是lvalue-reference转const,然后
function(var1); // rule#1 -> fine
function(45); // rule#3 -> fine
第3种情况是forwarding-reference,那么
function(var1); // rule#6 -> fine
function(45); // rule#7 -> fine
第4种情况是rvalue-reference,那么
function(var1); // rule#2 -> fail
function(45); // rule#5 -> fine
值得注意的是rvalue-reference和forwarding-reference的区别:
(强调我的)
function parameter of a function template declared as rvalue reference to cv-unqualified type template parameter of that same function template
在您的示例中,function(var1)
将推断 var1
用法为 lvalue
。要使其与 rvalue-based 模板兼容,您必须稍微帮助您的编译器:
template <typename U>
void function(const U&& var) {
std::cout << var << std::endl;
}
int main()
{
int var1 = 45;
function(std::move(var1)); // let convert lvalue to rvalue
function(45);
}
P.S。是的,你应该经常问自己 "do I really need that rvalue reference, or I'm perfectly fine with that old good lvalue ref?"