使用列表初始化初始化具有显式构造函数的结构向量时,正确的行为是什么?

问题描述

在 GCC 7.1 上,以下代码仅在显式构造函数具有认参数时才编译。运行时,b的大小为1。没有认参数,编译错误

在 Clang 上,代码以任何一种方式编译。当它运行时,b 的大小为 0。这是因为一个空向量被复制构造到 b 中。

两者都使用 C++17 进行了测试。

#include <stdio.h>
#include <vector>
#include <iostream>

    struct TestStruct {
        TestStruct(){}
    };
    struct TestStructExplicit {
#if 1
        explicit TestStructExplicit(int x=0){}
#else
        explicit TestStructExplicit(int x){}
        explicit TestStructExplicit(){}
#endif
    };

int main()
{
    //note the nested braces
    std::vector<TestStruct> a({{}});
    std::vector<TestStructExplicit> b({{}});

    std::cout << "SIZE a " << a.size() << std::endl;
    std::cout << "SIZE b " << b.size() << std::endl;
}

相关的 Godbolt 链接 https://godbolt.org/z/s5banG54G 与 GCC 和 Clang 的输出

根据标准,这里的正确行为是什么?我认为下面的 C++17 标准段落说不能使用显式构造函数,这是否意味着这是 GCC 错误? -

16.3.1.7 列表初始化[over.match.list] 1 当非聚合类类型 T 的对象被列表初始化时,11.6.4 指定重载决议 根据本节的规则执行,重载决议分两个阶段选择构造函数: (1.1) — 最初,候选函数是类 T 的初始化列表构造函数 (11.6.4) 和 参数列表由作为单个参数的初始值设定项列表组成。 (1.2) — 如果找不到可行的初始化列表构造函数,则再次执行重载解析,其中 候选函数是类 T 的所有构造函数,参数列表由元素组成 的初始化列表。 如果初始值设定项列表没有元素并且 T 具有认构造函数,则省略第一阶段。在复制列表初始化中,如果选择了显式构造函数,则初始化是格式错误的。 [注:这不同于 其他情况 (16.3.1.3,16.3.1.4),其中只考虑转换构造函数进行复制初始化。 仅当此初始化是重载解析的最终结果的一部分时,此限制才适用。 — 尾注 ]

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)