c++ - 值初始化 : MSVC vs clang

标签 c++ visual-studio initialization clang language-lawyer

#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 members and bases (since C++17) are initialized by 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 的默认构造函数,但它被声明为 explicitcopy-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/

相关文章:

c++ - 如何将多种数据类型接受到我的输入流中?

visual-studio - 在 Visual Studio 2017 中更新 PowerShell 版本

c# - 您的步入请求导致属性或运算符的自动跨步

c - 使数组显示错误值的结构

c++ - 初始化期间运行时类方法替换

iphone - 为什么我的 Application Delegate 中的类变量没有被实例化?

c++ - VC++ 9 QT 项目,转换为 Eclipse CDT

c++ - C代码的半随机慢度

C++ - 在寻路中对 std::vector 进行排序

c# - 使用 C# 编译的可执行文件有什么?