The left-hand operand of an assignment operator must be a modifiable lvalue. For example, given
int i = 0, j = 0, k = 0; // initializations, not assignment
const int ci = i; // initialization, not assignment
Each of these assignments is illegal:
1024 = k; // error: literals are rvalues
i + j = k; // error: arithmetic expressions are rvalues
ci = k; // error: ci is a const (nonmodifiable) lvalue
The result of an assignment is its left-hand operand, which is an lvalue. The type of the result is the type of the left-hand operand. If the types of the left and right operands differ, the right-hand operand is converted to the type of the left:
k = 0; // result: type int, value 0
k = 3.14159; // result: type int, value 3
Under the new standard, we can use a braced initializer list (§ 2.2.1, p. 43) on the right-hand side:
k = {3.14}; // error: narrowing conversion
vector<int> vi; // initially empty
vi = {0,1,2,3,4,5,6,7,8,9}; // vi now has ten elements, values 0 through 9
If the left-hand operand is of a built-in type, the initializer list may contain at most one value, and that value must not require a narrowing conversion (§ 2.2.1, p. 43).
For class types, what happens depends on the details of the class. In the case of vector
, the vector
template defines its own version of an assignment operator that can take an initializer list. This operator replaces the elements of the left-hand side with the elements in the list on the right-hand side.
Regardless of the type of the left-hand operand, the initializer list may be empty. In this case, the compiler generates a value-initialized (§ 3.3.1, p. 98) temporary and assigns that value to the left-hand operand.