赋值运算符左侧必须是可修改的左值;字面量、临时对象、右值、const左值、非引用返回的函数调用、复合表达式结果等均不可用。

赋值运算符 的左侧必须是一个可修改的左值(modifiable lvalue)。不是所有左值都行,更不是所有表达式都行。直接说结论:右值、常量左值、临时对象、字面量、函数调用返回非引用类型、以及多数复合表达式,都不能出现在 = 左侧。
哪些表达式明确不能作为 = 左侧?
编译器报错时常见提示是 error: lvalue required as left operand of assignment,意思是“需要左值作为赋值左侧操作数”。以下几类表达式一定不行:
-
42、"hello"、true等字面量(纯右值) -
x + y、x * 2、func()(若func()返回int而非int&)——这类计算结果是临时值,无内存地址 -
const int a = 5;中的a——它是左值,但不可修改,所以a = 10;编译失败 -
*p + 1、arr[i] + 1——加法结果是右值,哪怕arr[i]本身是左值 -
std::move(x)——它显式把x转为右值引用,结果是右值,不能再赋值给它(std::move(x) = y;非法)
注意:&x 是右值(指针本身是临时的),所以 &x = &y; 也非法 —— 你不能给“取地址的结果”再赋值。
func() 能不能当左值?看返回类型
关键不在“是不是函数调用”,而在返回值类型是否为左值引用:
立即学习“C++免费学习笔记(深入)”;
-
int func() { return 42; }→ 返回int(右值),func() = 10;❌ 编译失败 -
int& func() { static int x; return x; }→ 返回int&(左值引用),func() = 10;✅ 合法,等价于给那个static int赋值
同理:vec[0] 可以赋值,是因为 std::vector::operator[] 返回 T&;而 vec.at(0) 同样返回 T&,也能赋值;但 vec.front() 若被声明为 const T&,则不可赋值。
容易误判的“看起来像变量”的表达式
这些写法看似有名字或能取地址,但仍是右值或不可修改:
-
(x)—— 加括号不改变值类别,x是左值,(x)还是左值;但(x + y)就是右值 -
std::string("abc")—— 临时对象,右值,std::string("abc") = "def";❌ -
++x是左值(返回的是x自身),但x++是右值(返回旧值的副本)→ 所以x++ = 5;❌,而++x = 5;✅ -
reinterpret_cast<int&>(y)是左值(强制转成引用),可用作左侧;但static_cast<int>(y)</int>是右值,不可
一个快速检验法:对表达式写 &(expr),如果能通过编译(且不触发 const 引用绑定临时对象等隐式转换),那它大概率是可修改左值;否则基本没戏。
最常被忽略的一点:左值性 ≠ 可修改性。const int x = 0; 中的 x 是左值,但不是可修改左值 —— 编译器会把它拦在 = 左侧之外。别只盯着“能不能取地址”,还得看“有没有 const 修饰”和“类型是不是引用”。


















