繁体   English   中英

复制构造函数与 std::initializer_list 构造函数

[英]Copy constructor vs std::initializer_list constructor

想象一下,我们有:

struct S {
  struct S {
  S() { printf("%s\n", __PRETTY_FUNCTION__); }
  S(const S&) { printf("%s\n", __PRETTY_FUNCTION__); }
  S(S&&) { printf("%s\n", __PRETTY_FUNCTION__); }
  ~S() { printf("%s\n", __PRETTY_FUNCTION__); }

  S(std::initializer_list<S>) { printf("%s\n", __PRETTY_FUNCTION__); }
};

S s2{S{}};时应该调用哪些构造函数 ? gcc 和 clang 有不同的行为可以吗?

示例: https://godbolt.org/z/qQxyp5

gcc(主干)output:

S::S()
S::S(std::initializer_list<S>)
S::~S()
S::~S()

clang(主干)output:

S::S()
S::~S()

GCC 在这里是正确的; 列表初始化不允许 C++17 中的复制省略。

如果你做了S s2(S{}); ,这将只需要调用S的默认构造函数,因为[dcl.init]/17.6.1

如果初始化表达式是纯右值且源类型的 cv 非限定版本与目标的 class 相同 class,则初始化表达式用于初始化目标 ZA8CFDE6331BD59EB2AC96F8911C4B6。 [ 示例:T x = T(T(T())); 调用 T 默认构造函数来初始化 x。 —结束示例]

但是,这只适用于复制初始化和直接初始化。

S s2{S{}}; 是列表初始化,这是它自己完全独立的初始化形式,有自己的规则。 由于S不是一个聚合, [dcl.init.list]3.6将接管,它说:

否则,如果 T 是 class 类型,则考虑构造函数。 枚举适用的构造函数,并通过重载决议([over.match]、[over.match.list])选择最佳构造函数。

调用构造函数意味着使用一组特定的参数调用特定的 function。 这意味着必须使用纯右值S{}来初始化所选构造函数的参数。 这意味着您必须调用复制/移动构造函数。

也不允许常规的、无保证的省略。 [class.copy.elision]/1 给出了允许省略的 3 种情况: return localVariableNamethrow localVariableNamecatch(TypeName)如果 catch 与抛出的内容匹配。 这种情况显然不是这些,所以它不符合常规省略的条件。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM