【问题标题】:Perfect forwarding constructor and inheriting constructors完善的转发构造函数和继承构造函数
【发布时间】:2021-08-28 08:55:22
【问题描述】:

给定这个类层次结构:

#include <iostream>

class Base {
public:
    Base() = default;
    Base(const Base&) { std::cout << "  copy\n"; }
    
    template<typename T>
    Base(T&&) { std::cout << "  T&&\n"; }
};

class Sub : public Base {
public:
    using Base::Base;
};

is known 这段代码将打印T&amp;&amp;

// objects
Base varObj;
const Base constObj;
// invoking constructors
Base copy(varObj);              // T&&
Base move(std::move(constObj)); // T&&
Base number(42);                // T&&

为什么使用Sub 而不是Base “修复”问题?

// objects
Sub varObj;
const Sub constObj;
// invoking constructors
Sub copy(varObj);              // copy
Sub move(std::move(constObj)); // copy
Sub number(42);                // T&&

【问题讨论】:

  • fyi 注释掉 using Base::Base; 我得到 cland 和 gcc 之间的编译器差异 - 实时 - godbolt.org/z/WMG5xTodz
  • 移动 const 对象是一种不好的做法。由于源对象是常量,不能修改,所以你会得到一个副本,这会使代码产生误导。
  • @RichardCritten,有趣的是Sub number(42); 然后调用T&amp;&amp; 构造函数两次。但是,这只发生在-std=c++20 上。使用 C++17 GCC 会产生与 Clang 相同的错误。它看起来像是 GCC 10 引入的回归。

标签: c++ c++17 language-lawyer perfect-forwarding


【解决方案1】:

这是CWG2356:继承的构造函数仍然更适合非常量输入(因为需要限定转换),但它被 [over.match.funcs ]/8。这样做的部分原因是为了避免使任何继承构造函数的类都可以从其基类隐式转换。

Sub 复制构造函数(由您的两个初始化使用)仍有可能调用构造函数模板。但是,它的源参数是const Sub&amp;,所以它的基础子对象是const Base&amp;。这是 Base 复制构造函数的精确匹配,因此它在模板上被选中(否则会因为限定转换或引用类型而获胜)。

【讨论】:

  • 我认为问题不在于为什么 Sub 复制 ctor 调用 Base 复制 ctor。这就是为什么 Sub 复制 ctor 优先于继承的模板 ctor 的原因。
  • @HolyBlackCat:这是一个有效的观点。我在想象某种在这里不会发生的隐藏。我大大扩展了答案。
猜你喜欢
  • 1970-01-01
  • 2015-03-13
  • 2016-03-24
  • 2014-11-22
  • 1970-01-01
  • 2011-12-27
  • 2013-06-01
相关资源
最近更新 更多