C++ std::具有非常量引用参数的转发和构造函数

C++ std::具有非常量引用参数的转发和构造函数,c++,c++11,perfect-forwarding,C++,C++11,Perfect Forwarding,在对右值引用的简要介绍中,完美转发被认为是将右值5转发给具有非常量引用参数的构造函数的理想解决方案 但是: 编译。我做错了什么 完美转发是将右值5转发给具有非常量引用参数的构造函数的理想解决方案 我认为完美的转发并不意味着这一点。如果这篇文章是正确的,那么它就不能提出这样的建议,哪怕只是一点点 相反,这意味着它可以将右值引用作为右值转发,以便调用移动构造函数或接受右值引用的构造函数/函数 所以你应该试试这个: class X { public: X(int& i){

在对右值引用的简要介绍中,完美转发被认为是将右值5转发给具有非常量引用参数的构造函数的理想解决方案

但是:

编译。我做错了什么

完美转发是将右值5转发给具有非常量引用参数的构造函数的理想解决方案

我认为完美的转发并不意味着这一点。如果这篇文章是正确的,那么它就不能提出这样的建议,哪怕只是一点点

相反,这意味着它可以将右值引用作为右值转发,以便调用移动构造函数或接受右值引用的构造函数/函数

所以你应该试试这个:

class X {
public:
    X(int& i){
        std::cout<<"X("<<i<<")\n";
    }

    //this is a constructor which takes rvalue references
    X(int&& i){ 
        std::cout<<"X("<<i<<")\n";
    }
};
X类{
公众:
X(内部和一级){

std::cout不能将右值绑定到非常量左值引用。本文不建议使用完美转发,因为这是不可能的。完美转发将左值作为左值转发,将右值作为右值转发:

这里,forward保留了 已传递给工厂。如果将右值传递给工厂,则 rvalue将在forward的帮助下传递给T的构造函数 类似地,如果将左值传递给工厂,则 作为左值转发给T的构造函数


由于示例中的构造函数只接受左值,因此只能将左值传递到factory函数中。传递右值会将其作为右值转发,这将是格式错误的,因为无法将右值传递给该构造函数。

忽略右值引用一秒钟,而假装这是允许的:

void modify_int(int& i)
{
    i = 1;
}

void foo(int& x)
{
    modify_int(x); // okay, modify_int references x
}

int i = 7;
foo(i); // makes i = 1

// illegal in standard C++, cannot bind a temporary to a non-const reference
foo(5); // makes the temporary integer equal to 1

可以看到临时对象被修改,这是完全好的。但是,这种绑定在C++中是非法的,因为它通常不需要(它看起来好像5毕竟被更改为1)。 rvalue引用所做的一切都是支持将临时值绑定到引用,但这是安全的,因为我们知道我们正在处理一个应被视为临时值的值:

void modify_int(int& i)
{
    i = 1;
}

void foo(int&& x)
{
    modify_int(x); // okay, modify_int references x
}

int i = 7;
foo(std::move(i)); // makes i = 1 (std::move makes it an rvalue)

// legal in C++11, temporary is bound to rvalue-reference
foo(5); // makes the temporary integer equal to 1
请注意,在此版本的
foo
中,传递到
modify_int
仍然很好。一旦进入函数,它是右值引用而不是左值引用这一事实就无关紧要了:我们仍然有一个对象要引用:

void测试(int&i){}//测试的左值版本
无效测试(int&&i){}//测试的右值版本
模板
无效foo(T&x)
{
//如果x是一个左值,向前什么也不做;
//如果x是一个右值,则向前std::移动它
测试(标准:正向(x));
}
int i=7;
foo(i);//调用test的左值版本
foo(5);//调用测试的右值版本

没有转发的代码类似于我回答中的第二个代码段。一旦进入
工厂
函数,
a1
只是一个常规的左值,绑定到构造函数引用很好。但是通过转发,它会变回右值(因为
工厂(5)
使用右值调用它),无法绑定到左值引用,从而导致错误。

+1对于
,在这种情况下,移动构造函数没有多大意义
void modify_int(int& i)
{
    i = 1;
}

void foo(int& x)
{
    modify_int(x); // okay, modify_int references x
}

int i = 7;
foo(i); // makes i = 1

// illegal in standard C++, cannot bind a temporary to a non-const reference
foo(5); // makes the temporary integer equal to 1
void modify_int(int& i)
{
    i = 1;
}

void foo(int&& x)
{
    modify_int(x); // okay, modify_int references x
}

int i = 7;
foo(std::move(i)); // makes i = 1 (std::move makes it an rvalue)

// legal in C++11, temporary is bound to rvalue-reference
foo(5); // makes the temporary integer equal to 1
void test(int& i) {} // lvalue version of test
void test(int&& i) {} // rvalue version of test

template <typename T>
void foo(T&& x)
{
    // if x was an lvalue, forward does nothing;
    // if x was an rvalue, forward std::move's it 
    test(std::forward<T>(x)); 
}

int i = 7;
foo(i); // calls lvalue version of test

foo(5); // calls rvalue version of test