为什么仅在列表初始化的情况下才会出现缩小转换警告?

时间:2016-12-25 14:00:20

标签: c++ c++11 initialization list-initialization narrowing

我有以下代码:

class A
{
    public:
        A(const unsigned int val) : value(val) {}

        unsigned int value;
};

int main()
{
    int val = 42;
    A a(val);
    A b{val};       // <--- Warning in GCC, error in Microsoft Visual Studio 2015

    return 0;
}

为什么仅在列表初始化使用的情况下才会出现缩小转换警告?

3 个答案:

答案 0 :(得分:17)

list initialization是自C ++ 11以来引入的,其功能是禁止在内置类型之间隐式缩小转换。与此同时,另外两个&#34;旧式&#34; (从C ++ 98开始)初始化表单使用括号和等号

int val = 42;
A a(val);
A a = val;

不要改变他们的行为以符合列表初始化,因为这可能会破坏大量遗留代码库。

答案 1 :(得分:9)

根据标准,缩小转换在此上下文中是非法的。在其他情况下,它们是合法的。 (通过“非法”,我的意思是使程序格式不正确)。

该标准要求编译器在该特定情况下(使程序格式错误)发出诊断。发出诊断后编译器的作用是标准的未定义。

MSVC选择暂停编译。 Gcc选择发出鼻子恶魔假装程序有意义,并进行转换,并继续编译。

就标准而言,警告和错误都是诊断。传统上,错误就是编译器停止编译之前所谓的诊断。

另请注意,编译器可以随时发出诊断信息。

当您执行某些操作时,传统上使用警告,标准规定是一个格式良好的程序,但编译器作者认为不明智,并且当标准检测到格式错误的程序时出现错误,但大多数编译器都没有严格执行。

答案 2 :(得分:0)

其他答案已经解释了警告背后的原因。

这是解决此警告/错误的方法。创建一个以initializer_list为参数的构造函数。

A(std::initializer_list<int> l) : value(*(l.begin())) { 
    cout << "constructor taking initializer list called\n";
}