21
#include <iostream>

struct X {
    X(std::initializer_list<int> list) { std::cout << "list" << std::endl; }
    X(float f) { std::cout << "float" << std::endl; }
};

int main() {
    int x { 1.0f };
    X a(1);     // float (implicit conversion)
    X b{1};     // list
    X c(1.0f);  // float
    X d{1.0f};  // list (narrowing conversion) ARG!!!

    // warning: narrowing conversion of '1.0e+0f' from 'float' to 'int'
    // inside { } [-Wnarrowing]
}

是否有任何其他方法可以std::initializer_list从重载列表中删除(即,使非列表 ctor 更有利)而不是使用 () 初始化,或者至少禁止发生缩小转换(除了将警告变成错误)?

我使用的是使用 GCC 4.8 的http://coliru.stacked-crooked.com/编译器。

4

4 回答 4

20

实际上,在大括号列表初始化程序中包含缩小转换的程序是格式错误的。我不确定为什么编译器只是给你一个警告,但它肯定应该在这里发出一个错误(FWIW,Clang 这样做)。

另请注意,这也是一种缩小(因此也是非法的)转换:

int x { 1.0f }; // ERROR! Narrowing conversion required

根据 C++11 标准的第 8.5.4/3 段:

类型 T 的对象或引用的列表初始化定义如下:

— 如果T是聚合,则执行聚合初始化(8.5.1)。[...]

— 否则,如果初始化列表没有元素 [...]

— 否则,如果Tstd::initializer_list<E>, [...]

— 否则,如果T是类类型,则考虑构造函数。枚举适用的构造函数,并通过重载决议(13.3、13.3.1.7)选择最佳构造函数。如果需要缩小转换(见下文)来转换任何参数,则该程序格式不正确。[...]

更准确地说,标准只说在这种情况下需要“诊断”,而警告是一种诊断,因此编译器的行为是符合要求的——但我相信发出错误会是更好的行为。

于 2013-06-05T12:18:47.937 回答
3

这看起来像一个编译器错误。您应该收到错误而不是警告。大括号初始化不应该隐式缩小。

来自标准(§ 8.5.4)

struct B {
  B(std::initializer_list<int>);
};
B b1 { 1, 2 }; // creates initializer_list<int> and calls constructor
B b2 { 1, 2.0 }; // error: narrowing
于 2013-06-05T12:21:14.663 回答
2

你可以实现你想要的std::enable_if

#include <iostream>
#include <type_traits>

struct X {
    template<typename T, typename = typename std::enable_if<std::is_same<T,int>::value>::type>
    X(std::initializer_list<T>) { std::cout << "list" << std::endl; }
    X(float) { std::cout << "float" << std::endl; }
};

int main() {
    X a(1);     // float (implicit conversion)
    X b{1};     // list
    X c(1.0f);  // float
    X d{1.0f};  // float (yay)
}

适用于g++4.8和 clang 3.2

于 2013-06-05T16:59:52.043 回答
0

您可以使用-Wno-c++11-narrowing关闭错误:

这是一个示例测试程序:

#include <cstdint>

struct foo {
    int32_t a;
};

void foo(int64_t val) {
    struct foo A = { val };
}

使用 clang++-3.8 编译-std=c++11,我们得到声明的错误:

在此处输入图像描述

添加-Wno-c++11-narrowing,金色的沉默:-)

在此处输入图像描述

当然,收窄问题可能会在以后再次困扰您,但有时可能更容易将技术债务的痛苦推迟到以后。ymmv :-)

于 2016-11-26T23:17:14.627 回答