无法理解为什么完美转发不起作用
Cannot understand why perfect forwarding is not working
我想了解完美转发是如何工作的,但我不明白为什么在下面的代码中调用了复制构造函数
#include <utility>
#include <iostream>
using std::cout;
using std::endl;
class Something {
public:
Something() = default;
Something(__attribute__((unused)) const Something& other) {
cout << "Copy constructor called" << endl;
}
Something(__attribute__((unused)) Something&& other) {
cout << "Move constructor called" << endl;
}
void print() {
cout << "Something::print() called" << endl;
}
};
void function_1(Something&& one) {
cout << "version two called" << endl;
Something inner{one};
inner.print();
}
void function_1(const Something& one) {
Something inner(one);
inner.print();
}
template <typename... T>
void test_function(T&&... ts) {
function_1(std::forward<T>(ts)...);
}
int main() {
const Something some1 {Something()};
test_function(some1);
test_function(Something());
return 0;
}
这会产生以下输出
Copy constructor called
Something::print() called
version two called
Copy constructor called
Something::print() called
更改代码以将 std::move
包含在右值引用中有效,但我没想到需要它。当引用是右值引用时,应该自动调用正确的构造函数,对吧?解析了正确的引用,但调用了错误的构造函数。任何帮助将不胜感激!
右值引用绑定到右值。它本身不是右值,因为它有一个名字。
但是默认情况下,任何在使用时有名称的东西都是左值,甚至是右值引用。您的代码可以使用 Something&& one
三次,如果第一次隐式使用 move
s,您将被搞砸。
相反,它在使用时是左值(默认情况下),并且绑定到右值。
当你想发出信号时,你不再需要它的状态持续存在,std::move
它。
完美转发可用于编写您的两个 function_1
,方法是将 std::forward<Blah>(blah)
放在您想从 blah 移动的位置(如果它是右值引用)。
现在上面全是谎言,因为有 xvalues prvalues lvalues 等 -- 标准更复杂。例如,在 return 语句中使用变量可以将命名值转换为右值。但基本的经验法则值得了解:它有一个名称,它是一个左值(除非显式转换或过期)。
此代码将调用复制构造函数,而不是移动构造函数。
void function_1(Something&& one) {
cout << "version two called" << endl;
Something inner{one};
inner.print();
}
此代码调用移动构造函数。
void function_1(Something&& one) {
cout << "version two called" << endl;
Something inner{std::move(one)};
inner.print();
}
表达式 one
在技术上是一个左值。它指的是右值引用。但要真正获得右值引用,您必须使用 std::move
。通常任何有名字的东西都是左值。未命名的临时对象,例如 main()
中的 Something()
表达式:
test_function(Something());
可以是右值,并且可以在不使用 std::move
的情况下调用移动。
我想了解完美转发是如何工作的,但我不明白为什么在下面的代码中调用了复制构造函数
#include <utility>
#include <iostream>
using std::cout;
using std::endl;
class Something {
public:
Something() = default;
Something(__attribute__((unused)) const Something& other) {
cout << "Copy constructor called" << endl;
}
Something(__attribute__((unused)) Something&& other) {
cout << "Move constructor called" << endl;
}
void print() {
cout << "Something::print() called" << endl;
}
};
void function_1(Something&& one) {
cout << "version two called" << endl;
Something inner{one};
inner.print();
}
void function_1(const Something& one) {
Something inner(one);
inner.print();
}
template <typename... T>
void test_function(T&&... ts) {
function_1(std::forward<T>(ts)...);
}
int main() {
const Something some1 {Something()};
test_function(some1);
test_function(Something());
return 0;
}
这会产生以下输出
Copy constructor called
Something::print() called
version two called
Copy constructor called
Something::print() called
更改代码以将 std::move
包含在右值引用中有效,但我没想到需要它。当引用是右值引用时,应该自动调用正确的构造函数,对吧?解析了正确的引用,但调用了错误的构造函数。任何帮助将不胜感激!
右值引用绑定到右值。它本身不是右值,因为它有一个名字。
但是默认情况下,任何在使用时有名称的东西都是左值,甚至是右值引用。您的代码可以使用 Something&& one
三次,如果第一次隐式使用 move
s,您将被搞砸。
相反,它在使用时是左值(默认情况下),并且绑定到右值。
当你想发出信号时,你不再需要它的状态持续存在,std::move
它。
完美转发可用于编写您的两个 function_1
,方法是将 std::forward<Blah>(blah)
放在您想从 blah 移动的位置(如果它是右值引用)。
现在上面全是谎言,因为有 xvalues prvalues lvalues 等 -- 标准更复杂。例如,在 return 语句中使用变量可以将命名值转换为右值。但基本的经验法则值得了解:它有一个名称,它是一个左值(除非显式转换或过期)。
此代码将调用复制构造函数,而不是移动构造函数。
void function_1(Something&& one) {
cout << "version two called" << endl;
Something inner{one};
inner.print();
}
此代码调用移动构造函数。
void function_1(Something&& one) {
cout << "version two called" << endl;
Something inner{std::move(one)};
inner.print();
}
表达式 one
在技术上是一个左值。它指的是右值引用。但要真正获得右值引用,您必须使用 std::move
。通常任何有名字的东西都是左值。未命名的临时对象,例如 main()
中的 Something()
表达式:
test_function(Something());
可以是右值,并且可以在不使用 std::move
的情况下调用移动。