错误C2106:'=':左操作数必须是l值

时间:2013-07-29 17:58:09

标签: c++ templates vector

查看有关错误C2106的其他问题,我仍然对代码的问题感到遗憾。编译时我收到以下错误:

  

c:\ driver.cpp(99):错误C2106:' =' :左操作数必须是l值

     

c:\ driver.cpp(169):错误C2106:' =' :左操作数必须是l值

代码行如下:

payroll.at(i) = NULL; //Line 99
payroll.at(count++) = ePtr; //Line 169

我无法理解为什么会抛出此错误。在这个项目中,我将driver.cpp从一组员工对象指针更改为我制作的自定义Vector模板。我将Vector声明如下......

//Declare an Vector to hold employee object pointers
MyVector <employee*> payroll;

感谢任何帮助...

4 个答案:

答案 0 :(得分:12)

出现此错误的原因与您无法执行此操作的原因相同:

36 = 3;

您的Vector::at版本应该返回引用而不是值 左值称为左值,因为它们可以出现在赋值的左侧。 Rvalues不能出现在左侧,这就是我们称之为rvalues的原因。您无法将3分配给36,因为36不是左值,它是右值,是临时值。它没有内存地址。出于同样的原因,您无法将NULL分配给payroll.at(i)


您的定义:

template <class V> V MyVector<V>::at(int n)

应该是什么:

template<typename V> V& MyVector::at(std::size_t n)
template<typename V> const V& MyVector::at(std::size_t n) const

答案 1 :(得分:5)

消息说您尝试分配给不是左值的表达式。对于内置类型,您只能分配给左值(名称来自的位置:左值=可以在赋值运算符的左侧手侧的值,而rvalue =必须为的值)在赋值运算符的指针侧。)

那么左值或左值是多少?请考虑以下代码:

int a;
a = 3;

在这个赋值a中是一个左值(如果不是,编译器就会抱怨)。也就是说,表达式a指的是可以修改的对象。另一方面,3是一个右值,即基本上是一个值。当然你不能分配给3;编译器会抱怨语句3=a;与您在代码中得到的消息完全相同。

因此,作为第一近似值,左值指定对象,而右值指定值。请注意,对于表单

的分配也是如此
a = b;

其中b也是变量。这里发生的是所谓的左值转换左值:分配的不是对象b,而是它的当前值。

现在考虑以下情况:

int f();
f() = 3;

在这里你可能会争辩说函数f会返回一个对象(如果你使用某种用户定义的类型,你甚至可以看到它的构造/破坏)。但编译器仍然抱怨你得到的消息。为什么呢?

好吧,即使您考虑f返回一个对象,它也是一个临时对象,它会立即消失。因此,分配一个值没有多大意义,因为之后无论如何都无法做任何事情。

因此,这是第二条规则:

每当有一个产生临时对象的表达式时,C ++将该表达式定义为rvalue。

现在我们来看一下你没有展示的MyVector::at()的定义,但根据错误信息,它可能看起来与此相似:

template<typename T>
 T MyVector<T>::at(int i)
{
  return data[i];
}

这与上面f的格式基本相同,因为它还会返回T(在您的情况下为employee*)。这就是编译器抱怨的原因。

这个抱怨很有帮助:即使编译器不会抱怨,代码也不会像你几乎肯定想要的那样。 return语句返回对象data[i]副本。因此,如果语句payment.at(i)=NULL;已编译,实际发生的将是以下内容:

  1. 内部对象data[i](或者您在代码中调用它)是复制并返回临时副本。
  2. 声明分配了临时副本,但原始对象保持MyVector不变。
  3. 临时副本被破坏,不会留下任何痕迹。
  4. 这几乎肯定不是你想要的。您想要更改内部对象。为此,您必须将引用返回给该对象。引用引用它初始化的对象而不是复制。相应地,引用,即使返回,也是左值(因为C ++ 11有第二种类型的引用,行为不同,但我们不需要在此处理)。您更正后的功能将读取

    template<typename T>
     T& MyVector<T>::at(int i)
    {
      return data[i];
    }
    

    根据该定义,payment.at(i)=NULL;不仅可以编译,而且可以实际执行您想要的操作:将i中内部存储的payment指针更改为NULL。< / p>

答案 2 :(得分:3)

您的函数MyVector::at(unsigned)可能未正确声明,如下所示:

T MyVector::at(unsigned i) { /* implementation detail */ }

你想要的是它看起来像这样:

T& MyVector::at(unsigned i) { /* implementation detail */ }

注意引用参数(&amp;),它将通过引用返回任何元素,并允许表达式用作l值。

真正的问题是,为什么不使用std::vector呢?

答案 3 :(得分:0)

c ++中的术语l值表示'left-value'属于不正确的类型。由于您在其上使用赋值运算符,因此它必须是可以赋予​​新值的值,这意味着它不能是常量。最有可能的是,您对payroll.at()的调用返回的是常量值,而不是对实际值的引用。尝试为其分配新值将导致l值错误。