#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更有利),而不是使用()-initialization,或者至少禁止发生缩小转换(除了将警告变成错误之外)?
我使用的是http://coliru.stacked-crooked.com/编译器,它使用的是GCC 4.8。
发布于 2013-06-05 20:18:48
实际上,在大括号列表初始化器中包含缩小转换的程序是格式错误的。我不确定为什么编译器只是给你一个警告,但它肯定会在这里发出一个错误(FWIW,Clang does that)。
另请注意,这也是一个范围缩小(因此也是非法的)转换:
int x { 1.0f }; // ERROR! Narrowing conversion required根据C++11标准的第8.5.4/3段:
列表-T类型的对象或引用的初始化定义如下:
-如果T是聚合体,则执行聚合体初始化(8.5.1)。..。
-否则,如果初始值设定项列表没有元素...
-否则,如果T是std::initializer_list<E>的特殊化,...
-否则,如果T是类类型,则考虑构造函数。枚举适用的构造函数,并通过重载解析(13.3,13.3.1.7)选择最佳构造函数。如果需要进行缩小转换(见下文)来转换任何参数,则程序是格式错误的。..。
更准确地说,标准只说在这种情况下需要“诊断”,而警告是诊断,所以编译器的行为是一致的-但我相信发出错误会是更好的行为。
发布于 2013-06-05 20:21:15
这看起来像是一个编译器错误。你应该得到一个错误而不是警告。大括号初始化不应该隐式地缩小范围。
来自标准(§8.5.4)
结构B{ B(std::initializer_list);};B b1 { 1,2 };//创建initializer_list并调用构造函数B b2 { 1,2.0 };//错误:缩小
发布于 2013-06-06 00:59:52
您可以使用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和Clang3.2
https://stackoverflow.com/questions/16939471
复制相似问题