在C++11
之前,表达式的值分为左值和右值两种,其中右值就是我们理解中的字面值1、true、NULL
等。
自C++11
开始,表达式的值分为左值(lvalue, left value
)、将亡值(xvalue, expiring value
)、纯右值(pvalue, pure ravlue
)
一、如何判断左值、将亡值和纯右值
左值、将亡值和纯右值的概念比较烧脑,本文首先给出一个简单的方法来用做判定这三者:
int a = 1;
cout << type_id_with_cvr<decltype((a))>().pretty_name() << endl; // int&
cout << type_id_with_cvr<decltype((std::move(a)))>().pretty_name() << endl; // int&&
cout << type_id_with_cvr<decltype((1))>().pretty_name() << endl; // int
decltype((expr))
的返回值是T&
, 那么expr
是一个左值decltype((expr))
的返回值是T&&
, 那么expr
是一个将亡值decltype((expr))
的返回值是T
, 那么expr
是一个纯右值
二、左值、将亡值和纯右值对与函数调用的影响
首先,我们来看一下三者对于左值引用传参的影响:
void test(int&){
cout << __PRETTY_FUNCTION__ << endl;
}
test(a);
test(std::move(a)); // no matching function for call to 'test'
test(1); // no matching function for call to 'test'
可以看到左值引用的传参方式,无法接收expr为将亡值和纯右值, 需要提到的一点是,如果表达式为const int&
,那么三种传递方式都是合法的:
void test(const int&){
cout << __PRETTY_FUNCTION__ << endl;
}
test(a); // void test(const int &)
test(std::move(a)); // void test(const int &)
test(1); // void test(const int &)
如果传参方式为右值引用传参,那么情况如下:
void test(int&&){
cout << __PRETTY_FUNCTION__ << endl;
}
test(a); // no matching function for call to 'test'
test(std::move(a));
test(1);
如果上述三种传参方式都存在的话, 情况如下:
test(a); // void test(int &)
test(std::move(a)); // void test(int &&)
test(1); // void test(int &&)
总结
- 左值引用和右值引用得传参优先级别都高于常量引用
- 拷贝传参无法与上述三者任一共存,否则报错(
call to 'test' is ambiguous
)