【问题标题】:std::forward and copy constructorstd::forward 和复制构造函数
【发布时间】:2015-08-21 01:42:57
【问题描述】:

我最近开始学习 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
}

运行程序时的输出如下,

constructor.
constructor.
move constructor.
mc.val=6
copy constructor.

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

再次非常感谢您。

【问题讨论】:

  • MyClass(MyClass&amp;) 构造函数对许多类来说不是很有用。对于 RAII 模式,通常只遵循Rule Of Five
  • 谢谢你。我用 MyClass(MyClass&) 来检查这个复制构造函数没有被调用而不是 MyClass(const MyClass&) 虽然现在我知道在 Func() 中都没有调用。

标签: c++ templates c++11 perfect-forwarding


【解决方案1】:
Func(mc);

此调用将推断TMyClass&amp;。注意参考。这是由于在 C++ 中引入了完美转发的方式:如果相应的函数参数为一个左值表达式;否则(对于 xvalues 和 prvalues)它不会被推断为引用类型。

T 推导出的类型随后将与来自函数参数T&amp;&amp; t&amp;&amp; 进行引用折叠,以形成最终的函数参数类型。在Func(mc)T == MyClass&amp;的情况下,所以函数参数变成MyClass&amp; &amp;&amp;,折叠成MyClass&amp;

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

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

Func(MyClass());

这里,函数参数是纯右值表达式MyClass()T 将推导出为MyClass(无引用)。生成的函数模板实例化如下所示:

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

如果您想将函数参数复制/移动到局部变量中,可以使用 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;
}

【讨论】:

    猜你喜欢
    • 2017-01-31
    • 2012-11-03
    • 1970-01-01
    • 2014-04-15
    • 1970-01-01
    • 2011-04-27
    • 1970-01-01
    • 2013-10-13
    • 2018-03-12
    相关资源
    最近更新 更多