std :: move(T &&)和临时对象.临时来自哪里?

Rui*_*Fig 9 c++ c++11

我很好奇为什么我不能编译以下代码.

这是无意义的代码(我知道),但我最初在使用具有完美转发等模板的其他代码中遇到了问题.

我设法将问题缩小到std::move/ std::forward/ std::remove_reference,我很好奇为什么它首先需要一个临时的...

#include <utility>
#include <stdio.h>

struct Foo {
    Foo(Foo&& other) {
        printf("Foo::(Foo&&) %p\n", this);
    }
    Foo() {
        printf("Foo::() %p\n", this);
    }
    ~ Foo() {
        printf("Foo::~Foo() %p\n", this);
    }
};

void test(Foo&& t)
{
    // OK: Works fine and "f1" is is constructed with Foo::Foo(Foo&& other)
    // Foo f1 = std::move(t);

    // ERROR: Here it is trying to  bind a temporary Foo to a non-const lvalue
    // I can't figure out why it needs to create a temporary.
    Foo& f2 = std::move(t);
}

int main()
{
    Foo foo;
    test(std::move(foo));
}
Run Code Online (Sandbox Code Playgroud)

用Clang(3.7)编译,它给出了以下错误:

23 : error: non-const lvalue reference to type 'Foo' cannot bind to a temporary of type 'typename std::remove_reference<Foo &>::type' (aka 'Foo')
Foo& f2 = std::move(t);
^ ~~~~~~~~~~~~
1 error generated.
Compilation failed
Run Code Online (Sandbox Code Playgroud)

我理解我不能将临时绑定到非const引用,并且有很多问题可以解释为什么不允许这样做.

我希望代码只携带一个参考foomain最高Foo& f2,从而不需要临时.

Visual Studio接受代码,但GCC和Clang无法编译它; 虽然Visual Studio当然不那么严格.

Nia*_*all 9

我希望代码只携带一个参考foomain最高Foo& f2,从而不需要临时.

它并不像推进参考那么简单.这std::move是一个很好的方式来说"抛出这个左值,以便我可以将它用作右值".这实际上是为什么它不起作用.

cppreference ;

特别是,std::move生成一个标识其参数的xvalue表达式t.它static_cast与r值引用类型完全等效.

Foo& f2 需要一个左值来绑定引用,你提供一个右值引用 - 因此错误.

没有临时创建,在这方面错误消息具有误导性.您正在转换引用以允许值类别转换.完成这些转换后,可以通过适当的移动构造函数或赋值运算符执行移动.


作为旁注:VS可能允许这样做,因为它有一个非标准扩展,允许rvalues绑定到非const左值引用(但它会以更高的警告级别警告你/W4).


dav*_*mac 8

好:

Foo& f2 = std::move(t);
Run Code Online (Sandbox Code Playgroud)

f2是一个参考,所以你在哪里move?你根本就没有动.

std::move返回右值引用; 你不能将它赋给左值引用变量(考虑一个右值引用可以是对临时值的引用).因此,编译器抱怨您正在分配对临时的引用(因为std::move创建了编译器认为是对临时引用的引用,即rvalue引用).

暂时没有实际的创造; 它只是std::move返回一个右值引用,并且不允许将它赋给左值引用.(唯一可能的"临时"是t参数引用的那个,它被声明为右值引用;它会发生你的例子传递的东西不是临时的,通过move,但它可以很容易地通过参考实际临时).

所以简而言之,问题不是它需要一个临时的,而是你正在为一个左值引用变量分配一个右值引用(可能是指一个临时引用).Clang错误消息有点误导,因为它意味着存在临时,而右值引用可能实际上不是指临时引用.GCC代之以:

test2.cc: In function 'void test(Foo&&)': test2.cc:23:24: error:
invalid initialization of non-const reference of type 'Foo&' from an
rvalue of type 'std::remove_reference<Foo&>::type {aka Foo}'
     Foo& f2 = std::move(t);
Run Code Online (Sandbox Code Playgroud)