std :: forward和copy构造函数

mor*_*ora 3 c++ templates perfect-forwarding c++11

我最近开始学习C++.我在std :: forward上有一个关于左值引用和右值引用的问题.根据我的理解,以下代码中的Func(mc)假设由于模板参数推导规则而调用Func(T&t).并且应该在函数内部使用消息"复制构造函数"调用MyClass的复制构造函数.但是,当我运行程序时,我无法得到它.我检查了带有右值引用的std :: forwad,并且复制构造函数在其他行中运行良好.请帮我理解代码中发生的事情.如果我容易犯错误或误解,我很抱歉花时间.非常感谢你.

class MyClass {
public:
    MyClass() { printf("constructor.\n"); };
    MyClass(MyClass&) { printf("copy constructor.\n"); };
    MyClass(const MyClass&) { printf("const copy constructor.\n"); };
    MyClass(MyClass&&) { printf("move constructor.\n"); };
    int val = 3;
};

template <typename T>
void Func(T&& t) {
    T new_t_(std::forward<T>(t));
    new_t_.val *= 2;
};

main() {
    MyClass mc;
    Func(mc);  // lvalue <- Func(T&)
    Func(MyClass());  // rsvalue <- Func(T&&)
    printf("mc.val=%d\n", mc.val); // this is for check

    MyClass mc2(mc);  // this is for check of copy constructor
}
Run Code Online (Sandbox Code Playgroud)

我运行程序时输出如下,

constructor.
constructor.
move constructor.
mc.val=6
copy constructor.
Run Code Online (Sandbox Code Playgroud)

我认为它应该在第一个和第二个"构造函数"消息之间有"复制构造函数".

再一次非常感谢你.

dyp*_*dyp 5

Func(mc);
Run Code Online (Sandbox Code Playgroud)

这个电话会被推断TMyClass&.请注意参考.这是由于在C++中引入了完美转发的方式:如果相应的函数参数是lvalue-expression,则转发引用(如T&&函数参数)Func将被推导为左值引用; 否则(对于xvalues和prvalues),它不会被推断为引用类型.

推导出的类型T将使用&&函数参数进行引用折叠,T&& t以形成最终的函数参数类型.在这种情况下Func(mc),T == MyClass&函数参数变为MyClass& &&,折叠为MyClass&.

因为T == MyClass&,在这种情况下,局部变量的new_t_声明将声明一个引用.不会创建新对象:

template <>
void Func<MyClass&>(MyClass& t) {
    MyClass& new_t_(std::forward<MyClass&>(t));
    new_t_.val *= 2;
}
Run Code Online (Sandbox Code Playgroud)
Func(MyClass());
Run Code Online (Sandbox Code Playgroud)

这里,函数参数是prvalue-expression MyClass().T将被推断为MyClass(未经参考).生成的函数模板实例化如下所示:

template <>
void Func<MyClass>(MyClass&& t) {
    MyClass new_t_(std::forward<MyClass>(t));
    new_t_.val *= 2;
}
Run Code Online (Sandbox Code Playgroud)

如果要将函数参数复制/移动到局部变量中,std::decay可以使用元函数 - 或者更具体地说OP的问题是std::remove_reference元函数.例如

template <typename T>
void Func(T&& t) {
    using DT = typename std::decay<T>::type;
    DT new_t_(std::forward<T>(t));
    new_t_.val *= 2;
}
Run Code Online (Sandbox Code Playgroud)