C++ 初始化列表重载消歧

标签 c++ initializer-list compiler-bug

我有一个关于 C++ 初始化列表消歧的问题,它在 gcc、clang 和 Visual Studio 之间表现出不同的行为。
我想知道这是“未定义的行为”(不正确的程序)还是这些编译器之一有错误。任何的想法?
考虑以下声明:

class Arg
{
public:
    Arg(int i);
};

class Object
{
public:
    Object(const char* str, int i);
    Object(const char* str, const std::initializer_list<Arg>& args);
};
现在这种用法:
Object c("c", {4});
应该使用哪个构造函数?与 int 的那个(假设文字周围的大括号是多余的)或带有初始化列表的大括号(从 intArg 的隐式转换)。
GCC 10.2.0 选择初始化列表为 Arg 的构造函数.
Clang 11.2.2-2 选择带有 int 的构造函数并报告有关大括号的警告:
initlist.cpp:46:19: warning: braces around scalar initializer [-Wbraced-scalar-init]
    Object c("c", {4});
                  ^~~
Visual Studio 2019 16.8.6 选择带有 int 的构造函数没有警告( /W4 )。
从多数人的角度来看,带有 int 的构造函数赢了。另一方面,如果我们直接使用 std::initializer_list<int>而不是 std::initializer_list<Arg> (没有对 Arg 构造函数的隐式调用),所有三个编译器都选择带有初始化列表的构造函数。
由于歧义和行为的差异,无论如何都应该避免这种代码。但我很想知道谁错了?未定义的应用程序代码或编译器之一?
下面是完整的源代码,以防有人想尝试:
#include <iostream>

class Arg
{
public:
    int value;
    Arg(int i);
};

class Object
{
public:
    Object(const char* str, int i);
    Object(const char* str, const std::initializer_list<Arg>& args);
};


Arg::Arg(int i) : value(i)
{
    std::cout << "Arg(" << i << ")" << std::endl;
}

Object::Object(const char* str, int i)
{
    std::cout << "Object(\"" << str << "\", " << i << ")" << std::endl;
}

Object::Object(const char* str, const std::initializer_list<Arg>& args)
{
    std::cout << "Object(\"" << str << "\", {";
    bool comma = false;
    for (auto it = args.begin(); it != args.end(); ++it) {
        if (comma) {
            std::cout << ", ";
        }
        comma = true;
        std::cout << it->value;
    }
    std::cout << "})" << std::endl;
}

int main(int argc, char* argv[])
{
    Object a("a", 1);
    Object b("b", {2, 3});
    Object c("c", {4});
}
使用海湾合作委员会:
Object("a", 1)
Arg(2)
Arg(3)
Object("b", {2, 3})
Arg(4)
Object("c", {4})
使用 clang 和 VS:
Object("a", 1)
Arg(2)
Arg(3)
Object("b", {2, 3})
Object("c", 4)

最佳答案

{4}const std::initializer_list<Arg>&是用户定义的转换。{4}int是标准转换。
后者获胜。这是一个 GCC 错误。
列表初始化为 initializer_list当转换序列的形式相同时,胜过其他人。他们不在这里。

关于C++ 初始化列表重载消歧,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66372442/

相关文章:

c++ - 在 map 上使用查找功能时出错

c++ - 如何修复 "array rvalue"无法使用 gcc-4.8 和 clang-3.7 进行编译的问题?

Delphi 5 编译器错误返回接口(interface)指针而不是返回值

arrays - Delphi XE 字节数组索引

visual-c++ - 64 位指针减法、有符号整数下溢和可能的编译器错误?

c++ - 按动态条件/约束过滤图表

c++ - 如何防止eclipse c/c++单元测试遇到XML解析错误导致runner挂起?

c++ - 无法在 cbegin 中定义 initializer_list

c++ - std::set 需要多少额外内存(如果有的话)来存储它的元素 v.s.一个 std::vector?

c++ - 这个 C++ 函数如何返回两个值?