"Expression must be a modifiable lvalue"
위와 같은 오류를 다들 한 번씩은 마주친다.
VS 환경에서 마주치면 도대체 저게 어디서 나는 에러인지 파악하기조차 힘들다.
필자의 경우 lvalue의 l이 소문자 L인지, 대문자 I인지조차도 구분 못하고 있었다.
C++17 표준은 다음과 같이 식 값 범주를 정의합니다.
glvalue는 평가에서 개체, 비트 필드 또는 함수의 ID를 결정하는 식입니다.
prvalue는 계산에서 개체 또는 비트 필드를 초기화하거나 표시되는 컨텍스트에 지정된 대로 연산자의 피연산자 값을 계산하는 식입니다.
xvalue는 리소스를 재사용할 수 있는 개체 또는 비트 필드를 나타내는 glvalue입니다(일반적으로 수명이 거의 다 되었으므로). 예: rvalue 참조(8.3.2)와 관련된 특정 종류의 식은 반환 형식이 rvalue 참조이거나 rvalue 참조 형식에 대한 캐스트인 함수에 대한 호출과 같이 xvalue를 생성합니다.
lvalue는 xvalue가 아닌 glvalue입니다.
rvalue는 prvalue 또는 xvalue입니다.
이 부분에 대한 더 자세한 설명은 Values 문서에서 따로 진행하는 것으로 한다.
실제 에러메시지 등에서는 소문자를 사용한 표현 (lvalue, rvalue)로 나옵니다.
첫 접근은 쉽게 하는 게 좋으니, 직관적으로 접근해보자.
하지만 우리는 면접을 준비하고 있는 개발자 지망생이므로 조금 더 파고들어 보기로 한다.
int i;
const int j;
int i = 5 * 2;
int i
로 선언되며 생기는 i
는 Lvalue가 된다.5 * 2
부분이 Rvalue가 된다.int i = 1;
1 = i; // Error!
위 코드를 보면 당연히 2번째 줄에서 에러가 난다고 판단할 것이다. 그런데 왜 에러가 나는지 명확하게 말하기가 까다롭다.
정답을 말하자면, 등식의 왼쪽에 오는 값은 무조건 LValue여야 하기 때문이다.
Incorrect usage: The left operand must be an lvalue (C2106).
그럼 오른쪽에 LValue가 오는 것은 괜찮은가?
int i = 1;
int j = 1;
int i = j; // ?
LValue 및 RValue에는 어떤 값들이 있는지 알아보자.
int i = 1; // Numeric Literals
double j = 3.141592;
char k = 'a';
enum Numbers { Zero, One, Two, Three };
One = Two; // Incorrect usage: The left operand must be an lvalue (C2106)
int i = 1;
int j;
i + 1 = j; // Incorrect usage: The left operand must be an lvalue (C2106)
int i, *j;
j = &i; // Right Usage
i = &j; // Incorrect usage: the dereferenced pointer must be an lvalue
&3 // ??????
int a[3];
int *b = a;
int *b = 5; // Right usage
*(b + 1) = 7; // Right usage
int Count = 0;
++nCount = 5; // Right usage
int Count = 0;
nCount++ = 5; // Incorrect usage: The left operand must be an lvalue (C2106)
int& GetBig(int& a, int& b) // returning reference to make the function call an Lvalue
{
return ( a > b ? a : b );
}
void main()
{
int i = 10, j = 50;
GetBig( i, j ) *= 5;
// Here, j = 250. GetBig() returns the ref of j and it gets multiplied by 5 times.
}
int GetBig(int& a, int& b) // returning an int to make the function call an Rvalue
{
return ( a > b ? a : b );
}
void main()
{
int i = 10, j = 50;
const int& big = GetBig( i, j );
// Here, I am binding 'big' an Lvalue to the return value from GetBig(), an Rvalue.
int& big2 = GetBig(i, j); // Error. big2 is not binding to the return value as big2 is not const
}
int i, j;
i = 3;
j = 6;
i = j; // Right usage
7 = a; // Incorrect usage: The left operand must be an lvalue (C2106)
<참고>