暂时忽略右值引用,并假装这是允许的:
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-references 所做的都是启用临时值与引用的绑定,但很安全,因为我们知道我们正在处理一个应该被视为临时的值:
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,传递 tomodify_int仍然非常好。一旦进入函数,它是一个右值引用而不是一个左值引用这一事实是无关紧要的:我们仍然有一个对象要引用。模板中使用转发来保留值类别:
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
您没有转发的代码类似于我的答案中的第二个片段。一旦进入factory函数,a1它只是一个常规的左值,并且绑定到构造函数引用就好了。但是通过转发,它又变成了一个右值(因为factory(5)用右值调用它),它不能绑定到左值引用,从而导致错误。