C++ 无法理解为什么完美转发不起作用
我试图理解完美转发是如何工作的,但我无法理解为什么在下面的代码中调用复制构造函数C++ 无法理解为什么完美转发不起作用,c++,templates,c++11,perfect-forwarding,C++,Templates,C++11,Perfect Forwarding,我试图理解完美转发是如何工作的,但我无法理解为什么在下面的代码中调用复制构造函数 #include <utility> #include <iostream> using std::cout; using std::endl; class Something { public: Something() = default; Something(__attribute__((unused)) const Something& other) {
#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;
}
将代码更改为在右值参考中包含std::move
,这是可行的,但我没想到会需要它。当引用是右值引用时,应该自动调用正确的构造函数,对吗?解析了正确的引用,但调用了错误的构造函数。任何帮助都将不胜感激 右值引用绑定到右值。它本身不是右值,因为它有一个名称
但任何在使用点有名称的东西在默认情况下都是左值,即使是右值引用。您的代码可以使用某物&&one
三次,如果第一次使用隐式move
s,您将被拧死
相反,它在使用点是一个左值(默认情况下),并绑定到一个右值
当您想要发出信号表示不再需要其状态保持时,std::move
it
通过将std::forward(blah)
放在您希望从blah移动的位置(如果它是右值引用),完美转发可用于编写两个函数
现在上面充满了谎言,因为有xvalue,prvalue,lvalues等等——标准更复杂。例如,在return语句中使用变量可以将命名值转换为右值。但基本的经验法则是值得了解的:它有一个名称,它是一个左值(除非显式强制转换或过期)。右值引用绑定到右值。它本身不是右值,因为它有一个名称
但任何在使用点有名称的东西在默认情况下都是左值,即使是右值引用。您的代码可以使用某物&&one
三次,如果第一次使用隐式move
s,您将被拧死
相反,它在使用点是一个左值(默认情况下),并绑定到一个右值
当您想要发出信号表示不再需要其状态保持时,std::move
it
通过将std::forward(blah)
放在您希望从blah移动的位置(如果它是右值引用),完美转发可用于编写两个函数
现在上面充满了谎言,因为有xvalue,prvalue,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();
}
可以是右值,并且可以调用move而不使用std::move
此代码将调用copy-ctor,而不是move-ctor
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();
}
可以是右值,并且可以调用move而不使用std::move
这应该很容易理解:只需在构造函数上设置一个断点,当您点击它时,回溯将告诉您如何调用它。这是使用调试器可以解决的最简单的问题之一。@SamVarshavchik我知道如何调用它,但是调用了错误的重载!你怎么说?您确实知道需要显式使用std::move()来保留右值引用语义,对吗?@SamVarshavchik不是当它是右值引用时?这会使移动构造方式一直太显式,当您真正传递右值时,它不是显式的。但是,在这里,它不是右值。它是一个右值引用。右值!=右值引用。查找std::forward的功能。它对右值引用的专门化显式使用std::move()。这应该很容易理解:只需在构造函数上设置一个断点,当您点击它时,回溯将告诉您如何调用它。这是使用调试器可以解决的最简单的问题之一。@SamVarshavchik我知道如何调用它,但是调用了错误的重载!你怎么说?您确实知道需要显式使用std::move()来保留右值引用语义,对吗?@SamVarshavchik不是当它是右值引用时?这会使移动构造方式一直太显式,当您真正传递右值时,它不是显式的。但是,在这里,它不是右值。它是一个右值引用。右值!=右值引用。查找std::forward的功能。它对右值引用的专门化显式使用std::move()。但是为什么要调用复制构造函数呢?我不认为我完全理解到底发生了什么one
是一个右值。那么为什么不调用右值构造函数呢?现在发生的是,test\u函数(Something())
导致versiontwo调用了
行。(在函数1(Something&&)
实现的第一行)。然后复制发生。在内部某物{one}代码>。在test\u函数(Something())
中,它正确地匹配了作为r值引用的函数,否则您将看不到名为的版本2。只有当internal
被实例化时,您才能获得副本。我想将两个答案都标记为正确,但遗憾的是我无法做到这一点。我会投票给你的答案,给你同等的积分奖励!但是为什么要调用复制构造函数呢?我不认为我完全理解到底发生了什么one
是一个右值。那么为什么不调用右值构造函数呢?现在发生的是,test\u函数(Something())
导致versiontwo调用了
行。(在函数1(Something&&)
实现的第一行)。然后复制发生。在内部某物{one}代码>。在test\u函数(Something())
中,它正确地匹配了作为r值引用的函数,否则您将看不到名为的版本2。