为什么 `S x({})` 仅在 GCC 7/C++1z 模式下调用默认构造函数?
why `S x({})` invoke default constructor in GCC 7/C++1z mode only?
在下面的代码片段中,GCC 7 与 C++1z 模式调用默认构造函数,但 GCC/C++14 和 Clang/C++14,C++1z 调用初始化程序-列出构造函数。
此行为是否受到任何 C++1z 规范更改(可能 Guaranteed copy elision?)或 GCC 错误的影响?
#include <cstdio>
#include <initializer_list>
struct S {
S() { std::printf("DEF "); } // (1)
S(std::initializer_list<int> il) // (2)
{ std::printf("L=%zu ", il.size()); }
};
int main() {
S x({});
}
输出:
我认为这是一个 gcc 错误(提交为 80804)。 C++17 中 [dcl.init] 的规则顺序是:
If the destination type is a (possibly cv-qualified) class type:
- If the initializer expression is a prvalue and the cv-unqualified version of the source type is the same class as the class of the destination, the initializer expression is used to initialize the destination object.
第一个项目符号不适用。这里的初始化表达式是 {}
,它甚至不是表达式,所以它甚至没有 cv 非限定类型来与 S
进行比较。如果我们改为 S x(S{})
,则此项目符号 将 适用。
- Otherwise, if the initialization is direct-initialization, or if it is copy-initialization where the cv-unqualified version of the source type is the same class as, or a derived class of, the class of the destination, constructors are considered. The applicable constructors are enumerated ([over.match.ctor]), and the best one is chosen through overload resolution. The constructor so selected is called to initialize the object, with the initializer expression or expression-list as its argument(s). If no constructor applies, or the overload resolution is ambiguous, the initialization is ill-formed.
这是直接初始化,因此构造函数被视为每个 [over.match.ctor],这只是告诉构造函数重载。由于有一个 std::initializer_list
构造函数,该构造函数根据 [over.ics.rank] 获得优先级,因此选择了一个。
这里 C++14 和 C++17 之间的唯一区别是第一个项目符号的引入——无论如何都不适用,所以行为应该是相同的。
在下面的代码片段中,GCC 7 与 C++1z 模式调用默认构造函数,但 GCC/C++14 和 Clang/C++14,C++1z 调用初始化程序-列出构造函数。
此行为是否受到任何 C++1z 规范更改(可能 Guaranteed copy elision?)或 GCC 错误的影响?
#include <cstdio>
#include <initializer_list>
struct S {
S() { std::printf("DEF "); } // (1)
S(std::initializer_list<int> il) // (2)
{ std::printf("L=%zu ", il.size()); }
};
int main() {
S x({});
}
输出:
我认为这是一个 gcc 错误(提交为 80804)。 C++17 中 [dcl.init] 的规则顺序是:
If the destination type is a (possibly cv-qualified) class type:
- If the initializer expression is a prvalue and the cv-unqualified version of the source type is the same class as the class of the destination, the initializer expression is used to initialize the destination object.
第一个项目符号不适用。这里的初始化表达式是 {}
,它甚至不是表达式,所以它甚至没有 cv 非限定类型来与 S
进行比较。如果我们改为 S x(S{})
,则此项目符号 将 适用。
- Otherwise, if the initialization is direct-initialization, or if it is copy-initialization where the cv-unqualified version of the source type is the same class as, or a derived class of, the class of the destination, constructors are considered. The applicable constructors are enumerated ([over.match.ctor]), and the best one is chosen through overload resolution. The constructor so selected is called to initialize the object, with the initializer expression or expression-list as its argument(s). If no constructor applies, or the overload resolution is ambiguous, the initialization is ill-formed.
这是直接初始化,因此构造函数被视为每个 [over.match.ctor],这只是告诉构造函数重载。由于有一个 std::initializer_list
构造函数,该构造函数根据 [over.ics.rank] 获得优先级,因此选择了一个。
这里 C++14 和 C++17 之间的唯一区别是第一个项目符号的引入——无论如何都不适用,所以行为应该是相同的。