Lvalue因自动错误而衰减到右值

时间:2014-12-15 19:46:51

标签: c++ c++11 auto lvalue

如果问题标题不准确,我道歉 - 但我很难理解这里发生的事情。

考虑以下课程:

struct foo {
    foo(foo&);
};

以下内容没有错误:

void func(foo& f) {
    foo bar{f};
}

但是,当我使用auto时:

void func(foo& f) {
    auto bar = foo{f};
}

我得到(gcc):

test.cpp: In function ‘void func(foo&)’:
test.cpp:6:21: error: no matching function for call to ‘foo::foo(foo)’
test.cpp:6:21: note: candidate is:
test.cpp:2:5: note: foo::foo(foo&)
test.cpp:2:5: note:   no known conversion for argument 1 from ‘foo’ to ‘foo&’

(铛)

test.cpp:6:10: error: no matching constructor for initialization of 'bar'
    auto bar = foo{f};
         ^     ~~~~~~
test.cpp:2:5: note: candidate constructor not viable: expects an l-value for 1st argument
    foo(foo&);
    ^

有人可以解释为什么这是一个错误吗?

谢谢!

编辑:如果我向foo添加一个拷贝构造函数,它会起作用。但是,我认为变量声明+显式调用构造函数在' ='的右侧。语法是专门处理的,不是复制构造,而是直接初始化。

2 个答案:

答案 0 :(得分:8)

auto bar = foo{f};

auto推断为foo。随后,您的定义等同于

foo bar = foo{f};

您正在尝试创建foo类型的对象,该对象使用prvalue foo{f}进行复制初始化。

问题是foo的拷贝构造函数有一个非const左值引用作为参数,不可能绑定到右值。此外,由于您具有用户声明的复制构造函数,因此不会隐式定义移动构造函数。因此,没有构造函数可以使用foo{f},并且编译器会发出错误消息。

答案 1 :(得分:3)

auto bar = foo{f};

这是复制初始化,并且通过其语义,它需要复制构造函数的存在。但是,foo的复制构造函数采用非const引用,而非const引用不能绑定到临时引用,即foo{f}

解决方案是制作一个复制构造函数,它接受const引用,就像复制构造函数一样。