无法理解为什么完美转发不起作用

Cannot understand why perfect forwarding is not working

本文关键字:完美 转发 不起作用 为什么      更新时间:2023-10-16

我试图了解完美的转发是如何工作的,但我不明白为什么在下面的代码中调用复制构造函数

#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,你就会被搞砸。

相反,它是使用点的左值(默认情况下),并且绑定到右值。

当您想要发出信号时,不再需要其状态持续存在,请std::move它。

完美的转发可用于写入您的两个function_1,方法是在您想要从 blah 移动的点放置一个std::forward<Blah>(blah)(如果它是一个右值引用)。


现在上面充满了谎言,因为有x值prvalues lvalues等 - 标准更复杂。 例如,在 return 语句中使用变量可以将命名值转换为右值。 但基本的经验法则值得了解:它有一个名称,它是一个左值(除非显式强制转换或过期)。

此代码将调用复制 ctor,而不是移动 ctor。

void function_1(Something&& one) {
    cout << "version two called" << endl;
    Something inner{one};
    inner.print();
}

此代码调用移动 ctor。

void function_1(Something&& one) {
    cout << "version two called" << endl;
    Something inner{std::move(one)};
    inner.print();
}

表达式 one 在技术上是一个 l 值。它指的是右值引用。但是要实际获得右值引用,您必须使用 std::move .通常,任何有名称的东西都是 l 值。未命名的临时,例如您在main()中的Something()表达式:

test_function(Something());

可以是右值,并且可以在不使用std::move的情况下调用移动。