前向参考混淆

时间:2017-10-11 18:00:02

标签: c++ c++11 c++14

参考以下代码,我不明白为什么使用move constructorlvalue同时调用rvalue。当我将copy ctor传递给lvalue方法时,我希望打印push

#include <iostream>
#include <string>
#include <vector>
using namespace std;

class my_obj
{
public:
    my_obj()
    {
        cout << "default ctor\n";
    }

    my_obj(const my_obj& other)
    {
        cout << "copy ctor\n";
    }

    my_obj(my_obj&&  other)
    {
        cout << "move ctor\n";
    }      
};

class test
{
public:
    template<typename T>
    void push(T&& object)
    {
         print(forward<T>(object));
    }

    template<typename T>
    void print(T&& a)
    {
        cout << "move\n";
        my_obj temp = forward<T>(a);
    }

    template<typename T>
    void print(T& a)
    {
        cout << "val\n";
        my_obj temp = forward<T>(a);
    }
};


int main()
{
    my_obj obj;
    test f;

    f.push(obj); // why is move ctor called here? shouldnt it be copy ctor since not rvalue
    cout << "\nPUSHING TEMP\n\n";
    f.push(my_obj {});
}

输出:

default ctor
val
move ctor

PUSHING TEMP

default ctor
move
move ctor

2 个答案:

答案 0 :(得分:4)

在这里:

template<typename T>
void print(T& a)
{
    cout << "val\n";
    my_obj temp = forward<T>(a);
}

a不是转发引用,它是左值引用。类型T不是引用类型。因此forward<T>(a)move(a)的行为相同。转发引用的特殊情况是模板参数推导为引用类型,使用引用类型转发会产生左值。

您只想要my_obj temp = a;

答案 1 :(得分:2)

调用移动构造函数是因为您使用std::forward而没有转发引用(请不要这样做)。基本上,这条线是罪魁祸首:

my_obj temp = forward<T>(a);

此处Tmy_obj。请记住,std::forward只是一个荣耀的演员。在您的情况下,它相当于:

my_obj temp = static_cast<my_obj&&>(a);

因此,您将a转换为右值引用,并且rvalue具有移动语义,因此您可以看到正在调用的移动构造函数。你基本上得到了std::move的行为。