The message says that you try to assign to an expression which is not an lvalue. For built-in types, you can only assign to lvalues (that’s where the name comes from: lvalue = value that can be on the left hand side of the assignment operator, while rvalue = value that must be on the right hand side of the assignment operator).
So what is an lvalue or an rvalue? Consider the following code:
int a;
a = 3;
In this assignment a
is an lvalue (if it weren’t, the compiler would complain). That is, the expression a
refers to an object which can be modified. On the other hand, 3
is an rvalue, that is, basically a value. Of course you cannot assign to 3
; the compiler would complain about the statement 3=a;
with exactly the same message you got in your code.
So as a first approximation, an lvalue designates an object, while an rvalue designates a value. Note that this is also true for assignment of the form
a = b;
where b
also is a variable. What happens here is the so-called lvalue to rvalue conversion: What is assigned is not the object b
, but its current value.
Now consider the following case:
int f();
f() = 3;
Here you might argue that the function f
does return an object (if you use some user-defined type, you even can see its construction/destruction). But the compiler still complains with the message you got. Why?
Well, even if you consider f
to return an object, it is a temporary object which will go away immediately. So it does not make much sense to assign a value because you cannot do anything with it anyway afterwards.
Therefore here’s the second rule:
Whenever there’s an expression which produces a temporary object, C++ defines that expression as rvalue.
And now we come to the definition of MyVector::at()
which you did not show, but which, according to the error message, probably looks similar to this:
template<typename T>
T MyVector<T>::at(int i)
{
return data[i];
}
This has essentially the same form as f
above, as it also returns a T
(an employee*
in your case). This is why the compiler complains.
And that complaint is helpful: Even if the compiler wouldn’t complain, the code would not dio what you almost certainly intended. The return
statement returns a copy of the object data[i]
. Thus if the statement payment.at(i)=NULL;
had compiled, what would actually happen would be the following:
- The internal object
data[i]
(or however you called it in your code) is copied and the temporary copy returned. - The statement assigned that temporary copy, but leaves the original object in
MyVector
unchanged. - The temporary copy gets destructed, leaving no trace of your assignment.
This is almost certainly not what you wanted. You wanted to change the internal object. To do so, you have to return a reference to that object. A reference refers to the object it was initialized with instead of making a copy. Correspondingly, a reference, even when returned, is an lvalue (since C++11 there’s a second type of reference which behaves differently, but we don’t need to care about that here). Your corrected function then reads
template<typename T>
T& MyVector<T>::at(int i)
{
return data[i];
}
and with that definition, payment.at(i)=NULL;
not only compiles, but actually does what you want: Change the internally stored i
-th pointer in payment
to NULL
.
BoBaH26 30 / 30 / 5 Регистрация: 02.12.2010 Сообщений: 255 |
||||
1 |
||||
20.09.2011, 23:20. Показов 9086. Ответов 39 Метки нет (Все метки)
Здравствуйте, при попытке символьному элементу структуры (char name [30]) присвоить такой же символьный элемент выдается ошибка C2106 — левый операнд должен быть левосторонним значением. Вот фрагмент листинга, на всякий случай с описанием самой структуры:
Заранее спасибо!
0 |
794 / 546 / 61 Регистрация: 11.05.2010 Сообщений: 1,298 Записей в блоге: 1 |
|
20.09.2011, 23:37 |
2 |
BoBaH26, массивы массивам не присваиваются. Для копирования строк используйте strcpy.
0 |
186 / 186 / 21 Регистрация: 08.01.2011 Сообщений: 1,139 |
|
20.09.2011, 23:38 |
3 |
name — это указатель на строку.
0 |
30 / 30 / 5 Регистрация: 02.12.2010 Сообщений: 255 |
|
20.09.2011, 23:39 [ТС] |
4 |
Сейчас попробую…
0 |
talis |
20.09.2011, 23:40
|
Не по теме: Chelioss, это не указатель. Массив чистой воды
char name [30];
0 |
30 / 30 / 5 Регистрация: 02.12.2010 Сообщений: 255 |
|
20.09.2011, 23:41 [ТС] |
6 |
Chelioss, так а как тогда? Через copy, как сказал talis?
0 |
186 / 186 / 21 Регистрация: 08.01.2011 Сообщений: 1,139 |
|
20.09.2011, 23:41 |
7 |
Не по теме: Chelioss, это не указатель. Массив чистой воды Не правильно. name — это указатель на массив, причем name — это константный указатель.
0 |
30 / 30 / 5 Регистрация: 02.12.2010 Сообщений: 255 |
|
20.09.2011, 23:41 [ТС] |
8 |
Да, кстати, не заметил, это символьный массив.
0 |
186 / 186 / 21 Регистрация: 08.01.2011 Сообщений: 1,139 |
|
20.09.2011, 23:42 |
9 |
Chelioss, так а как тогда? Через copy, как сказал talis? Да, либо самому вручную каждый элемент присвоить.
0 |
30 / 30 / 5 Регистрация: 02.12.2010 Сообщений: 255 |
|
20.09.2011, 23:43 [ТС] |
10 |
Да, либо самому вручную каждый элемент присвоить. Ну это не есть хорошо, т.к. у меня массив из структур, а мне его надо отсортировать, и для каждого MasList[i].name писать вручную…. Можно с ума сойти..
0 |
794 / 546 / 61 Регистрация: 11.05.2010 Сообщений: 1,298 Записей в блоге: 1 |
|
20.09.2011, 23:44 |
11 |
Chelioss, где он объявлен как указатель? min — это объект типа List. В struct List есть объявление char name [30];. Соответственно, min.name — массив char из 30 элементов. Добавлено через 24 секунды
Да, либо самому вручную каждый элемент присвоить. Не имеет смысла. Есть библиотечные функции для копирования строк и памяти.
0 |
Chelioss 186 / 186 / 21 Регистрация: 08.01.2011 Сообщений: 1,139 |
||||
20.09.2011, 23:46 |
12 |
|||
Ну это не есть хорошо, т.к. у меня массив из структур, а мне его надо отсортировать, и для каждого MasList[i].name писать вручную…. Можно с ума сойти.. Можно самому написать функцию подобной strcpy. Ну или используйте strcpy. Добавлено через 1 минуту
Chelioss, где он объявлен как указатель?
Конечно, надо по другому объяснять, а не примеры приводить, но я просто знаю без доказательства)
0 |
30 / 30 / 5 Регистрация: 02.12.2010 Сообщений: 255 |
|
20.09.2011, 23:48 [ТС] |
13 |
Не совсем понял с пунктом 1
0 |
794 / 546 / 61 Регистрация: 11.05.2010 Сообщений: 1,298 Записей в блоге: 1 |
|
20.09.2011, 23:50 |
14 |
char *ptr = name; // работает. Почему? Потому, что name — это char *. Работает благодаря приведению типов. Объявление смотрите — char name[30].
0 |
Chelioss 186 / 186 / 21 Регистрация: 08.01.2011 Сообщений: 1,139 |
||||
20.09.2011, 23:50 |
15 |
|||
Не совсем понял с пунктом 1 Вы про
?
0 |
talis 794 / 546 / 61 Регистрация: 11.05.2010 Сообщений: 1,298 Записей в блоге: 1 |
||||
20.09.2011, 23:52 |
16 |
|||
Какой тип объявлен?
0 |
186 / 186 / 21 Регистрация: 08.01.2011 Сообщений: 1,139 |
|
20.09.2011, 23:52 |
17 |
Работает благодаря приведению типов. Объявление смотрите — char name[30]. А что такое name? без []? Он по вашему мнению вообще не существует без []. А со [] — это всего лишь i-тый символ, а не массив.
0 |
30 / 30 / 5 Регистрация: 02.12.2010 Сообщений: 255 |
|
20.09.2011, 23:54 [ТС] |
18 |
char *ptr = name;
0 |
794 / 546 / 61 Регистрация: 11.05.2010 Сообщений: 1,298 Записей в блоге: 1 |
|
20.09.2011, 23:55 |
19 |
Chelioss, по моему мнению (и позвольте мне самому его высказывать), name без [] — это массив из 30-ти char, как и объявлено выше. А к указателю оно приводится автоматически благодаря приведению типов. Добавлено через 24 секунды
char *ptr = name; Да. Адрес первого элемента массива name.
0 |
186 / 186 / 21 Регистрация: 08.01.2011 Сообщений: 1,139 |
|
20.09.2011, 23:59 |
20 |
talis
0 |
Okay, so, ignoring my lazy coding (this is just to get the program to work, I’ll clean it up after I get it working). I’ve set up a couple of if statements that will throw exceptions if I don’t get the input I’d like.
#include<string>
#include<iostream>
using namespace std;
int main()
{
bool flag = false;
int month, day, year;
void header();
class monthClassException
{
public:
monthClassException()
{
message = "Invalid Month";
}
monthClassException(string str)
{
message = str;
}
string what()
{
return message;
}
private:
string message;
};
class dayClassException
{
};
class yearClassException
{
};
header();
do
{
try
{
cout << "Please enter your date of birth (MM-DD-YYYY): " << endl;
cin >> month;
cin.ignore(10,'-');
cin >> day;
cin.ignore(10,'-');
cin >> year;
if (month > 12 || month < 1)
throw monthClassException("Invalid Month Entry");
if( ((month == 4 || month == 6 || month == 9 || month == 11) && day > 30) || day < 1)
throw dayClassException();
else if ( ((month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12 ) && day > 31) || day < 1)
throw dayClassException();
else if (month == 2 && year % 4 != 0 && day > 28)
throw dayClassException();
else if((month == 2 && year % 4 = 0) && day > 29)
throw dayClassException();
}
catch(monthClassException mCEO)
{
cout << mCEO.what() << endl;
system("pause");
}
catch(dayClassException)
{
cout << "Invalid Day Entered for Selected Month" << endl;
system("pause");
}
catch(yearClassException yCEO)
{
}
}while(!flag);
return 0;
}
I’m getting my error at that very last exception:
else if((month == 2 && year % 4 = 0) && day > 29)
throw dayClassException();
it’s saying that month is an invalid l-value (Why now? At the very end after I’ve already used it -catastrophically, I will admit.) It could be something really obvious that I fail to see because I’m the one who coded it, or it could be because my really really crazy if statements messed something up somewhere.
Any ideas?
Permalink
Cannot retrieve contributors at this time
description | title | ms.date | f1_keywords | helpviewer_keywords | ms.assetid |
---|---|---|---|---|---|
Learn more about: Compiler Error C2106 |
Compiler Error C2106 |
11/04/2016 |
C2106 |
C2106 |
d5c91a2e-04e4-4770-8478-788b98c52a53 |
Compiler Error C2106
‘operator’ : left operand must be l-value
The operator must have an l-value as its left operand.
The following sample generates C2106:
// C2106.cpp int main() { int a; 1 = a; // C2106 a = 1; // OK }
- Remove From My Forums
-
Question
-
Hi All,
class Bucket { public: Bucket() {count=0; label=-1; }; public: float label, count; void displayData(); float getLabel(); }; const int MAX=2000;
Bucket ang[MAX];ifstream inlabel(«Labels of Buckets.txt»);
k=0;
float labelset;
while(inlabel >> labelset && k<1023)
{
ang[k].getLabel() = labelset;
cout << ang[k].getLabel() << endl;
k++;
}inlabel.close(); float Bucket::getLabel() { return label; } Why it shows»error C2106: ‘=’ : left operand must be l-value»?? I don’t really understand what it means, sicne my label is defined as a float already.
Thanks a lot!
Thank you for replying! I love this forum!
-
Edited by
Saturday, August 9, 2008 12:05 AM
typo
-
Edited by
Answers
-
The easy fix is to have getLabel return a float& instead of a float, but then the name getLabel is a misnomer. So a better option would be to have separate member functions for getting and setting label:
class Bucket { public: Bucket() : label_(-1.0f), count_(0.0f) { } float getLabel() const { return label_; } void setLabel(float l) { label_ = l; } private: float label_; float count_; }; This is common enough that it is normal to elide the ‘get’ and ‘set’ part of the names, and distinguish between the methods only by their parameters and return types:
class Bucket { public: Bucket() : label_(-1.0f), count_(0.0f) { } float label() const { return label_; } void label(float l) { label_ = l; } private: float label_; float count_; }; -
Marked as answer by
Yan-Fei Wei
Wednesday, August 13, 2008 6:50 AM
-
Marked as answer by