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

问题描述 投票:2回答:1

想象我们有:

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(trunk)输出:

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

c(干)输出:

S::S()
S::~S()
c++ g++ c++17 clang++
1个回答
0
投票

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

如果您已完成S s2(S{});,则由于S,仅调用[dcl.init]/17.6.1的默认构造函数才需要这样做:

如果初始化程序表达式是prvalue,并且源类型的cv不合格版本与目标程序的类相同,则使用初始化程序表达式来初始化目标对象。 [示例:T x = T(T(T()));调用T的默认构造函数初始化x。 —示例]

但是,这仅适用于副本初始化和直接初始化。

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

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

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

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

© www.soinside.com 2019 - 2024. All rights reserved.