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

标签 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) {
        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 是可行的,但我没想到需要它。当引用是右值引用时,应该自动调用正确的构造函数,对吧?解析了正确的引用,但调用了错误的构造函数。任何帮助将不胜感激!

最佳答案

右值引用绑定(bind)到右值。它本身不是右值,因为它有一个名称。

但是默认情况下,任何在使用时有名称的东西都是左值,甚至是右值引用。您的代码可以使用 Something&& one三次,如果第一次隐式使用 move否则你会完蛋的。

相反,它在使用时是一个左值(默认情况下),并且绑定(bind)到一个右值。

当你想发出信号时,你不再需要它的状态持续存在,std::move

完美转发可以用来写你的function_1通过放置 std::forward<Blah>(blah)如果它是右值引用,则在您想从 blah 移动的位置。


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

关于c++ - 无法理解为什么完美转发不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35952950/

相关文章:

c++ - 图可排序性 C++

c++ - 在结构 C++ 中使用数组

c++ - 函数返回类型会影响重载的选择吗?

c++ - 对模板基类成员函数的 undefined reference

templates - 在所有错误检查完成之前,如何防止在 Go 中生成输出?

c++ - std::istream_iterator 停止前进

c++ - 将 const 和 decltype 与指针变量一起使用

c++ - 如何将堆栈分配的多态指针数组模板化为接口(interface),包括派生类型的相应指针?

c++ - 将 C++ 对象 move 到内存位置

c++ - 如何实现列表<T>::迭代器?