yoh*_*hjp 15 c++ gcc language-lawyer c++17
在下面的代码片段中,带有C++ 1z模式的GCC 7调用默认构造函数,但GCC/C++ 14和Clang/C++ 14,C++ 1z调用initializer-list构造函数.
此行为是否受到任何C++ 1z规范更改(可能是保证副本省略?)或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({});
}
Run Code Online (Sandbox Code Playgroud)
输出:
Bar*_*rry 17
我认为这是一个gcc bug(提交为80804).C++ 17中[dcl.init]的规则顺序是:
如果目标类型是(可能是cv限定的)类类型:
- 如果初始化表达式是prvalue且源类型的cv-nonqualified版本与目标类相同,则初始化表达式用于初始化目标对象.
第一颗子弹不适用.这里的初始化表达式是{}
,甚至不是表达式,所以它甚至没有cv-unqualified类型来进行比较S
.如果我们写了相反的话,这个子弹将适用S x(S{})
.
- 否则,如果初始化是直接初始化,或者如果它是复制初始化,其中源类型的cv-nonqualified版本与目标类相同的类或派生类,则考虑构造函数.枚举适用的构造函数([over.match.ctor]),并通过重载决策选择最佳构造函数.调用所选的构造函数来初始化对象,初始化表达式或表达式列表作为其参数.如果没有构造函数适用,或者重载决策是不明确的,则初始化是错误的.
这是直接初始化,因此构造函数被认为是[over.match.ctor],它只是告诉构造函数重载.由于有一个std::initializer_list
构造函数,每个[over.ics.rank]获得一个优先级,因此选择了一个.
这里C++ 14和C++ 17的唯一区别是引入了第一个子弹 - 无论如何都不适用,所以行为应该是相同的.