#include<cstddef>
template<typename T, std::size_t N>
struct A {
T m_a[N];
A() : m_a{} {}
};
struct S {
explicit S(int i=4) {}
};
int main() {
A<S, 3> an;
}
上面的代码在 MSVC (2017) 中编译得很好,但在 clang 3.8.0 中编译失败(clang++ --version && clang++ -std=c++14 -Wall -pedantic main.cpp
):
clang version 3.8.0 (tags/RELEASE_380/final 263969)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /usr/local/bin
main.cpp:6:15: error: chosen constructor is explicit in copy-initialization
A() : m_a{} {}
^
main.cpp:14:13: note: in instantiation of member function 'A<S, 3>::A' requested here
A<S, 3> an;
^
main.cpp:10:14: note: constructor declared here
explicit S(int i=4) {}
^
main.cpp:6:15: note: in implicit initialization of array element 0 with omitted initializer
A() : m_a{} {}
^
1 error generated.
clang 5.0 也拒绝编译这个:
<source>:6:17: error: expected member name or ';' after declaration specifiers
A() : m_a{} {}
^
<source>:6:14: error: expected '('
A() : m_a{} {}
^
2 errors generated.
如果我在 A
的构造函数中使用简单的括号(即 A() : m_a() {}
),它编译得很好。来自 cppreference我会怀疑两者都应该导致相同的结果(即值初始化)。我是否遗漏了什么或者这是其中一个编译器中的错误?
最佳答案
Clang 是正确的。
你的困惑来自:
From cppreference I would have suspected that both should result in the same (i.e. value initialization).
不,它们有不同的效果。请注意该页面中的注释:
In all cases, if the empty pair of braces {} is used and T is an aggregate type, aggregate-initialization is performed instead of value-initialization.
这意味着当使用花括号初始化列表进行初始化时,对于聚合类型,首选执行聚合初始化。用A():m_a{} {}
,而m_a
是一个数组,属于aggregate type ,然后 aggregate initialization而是执行:
(强调我的)
Each
direct public base, (since C++17)
array element, or non-static class member, in order of array subscript/appearance in the class definition, is copy-initialized from the corresponding clause of the initializer list.
和
If the number of initializer clauses is less than the number of members
and bases (since C++17)
or initializer list is completely empty, the remaining membersand bases (since C++17)
are initializedby their default initializers, if provided in the class definition, and otherwise (since C++14)
by empty lists, in accordance with the usual list-initialization rules (which performs value-initialization for non-class types and non-aggregate classes with default constructors, and aggregate initialization for aggregates).
这意味着剩余的元素,即 m_a
的所有 3 个元素将从空列表中复制初始化;对于空列表,将考虑 S
的默认构造函数,但它被声明为 explicit
; copy-initialization不会调用 explicit
构造函数:
copy-list-initialization (both explicit and non-explicit constructors are considered, but only non-explicit constructors may be called)
另一方面,A() : m_a() {}
执行 value initialization , 那么
3) if T is an array type, each element of the array is value-initialized;
然后
1) if T is a class type with no default constructor or with a user-provided or deleted default constructor, the object is default-initialized;
然后调用S
的默认构造函数来初始化m_a
的元素。 default initialization 是否是 explicit
无关紧要.
关于c++ - 值初始化 : MSVC vs clang,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48870550/