[英]Why doesn't the compiler warn about unsigned to signed conversion?
I recently got bit in the butt with this code: 我最近得到了这个代码:
std::size_t s = 10;
std::vector<int> v{s};
Rather than initialize with a size of 10, this initializes with a size of 1 with one element 10
. 而不是使用10的大小初始化,而是使用一个元素
10
初始化大小为1。 However, the vector has an explicit constructor that takes a std::size_t
. 但是,向量有一个显式构造函数,它采用
std::size_t
。 With all the hype about "use braces everywhere", I would expect many people have fallen into this trap. 随着所有关于“到处都使用括号”的炒作,我预计会有很多人陷入这个陷阱。 This could be avoided if the compiler simply warned that we were trying to turn a
size_t
into an int
. 如果编译器只是警告我们试图将
size_t
转换为int
,则可以避免这种情况。
Why isn't the compiler required to do this? 为什么编译器不需要这样做?
EDIT : My original code had const std::size_t s
. 编辑 :我的原始代码有
const std::size_t s
。 Apparently none of the compilers I use warn unless I remove the const. 显然,除非我删除const,否则我使用的编译器都不会发出警告。 Is this a bug?
这是一个错误吗?
No it is not a bug. 不,这不是一个bug。 See [dcl.init.list]/7 of N3337:
见N3337的[dcl.init.list] / 7:
A narrowing conversion is an implicit conversion
缩小转换是隐式转换
...
...
- from an integer type or unscoped enumeration type to an integer type that cannot represent all the values of the original type, except where the source is a constant expression and the actual value after conversion will fit into the target type and will produce the original value when converted back to the original type.
从整数类型或未范围的枚举类型到不能表示原始类型的所有值的整数类型,除非source是常量表达式,并且转换后的实际值将适合目标类型并且将在生成原始值时生成原始值转换回原始类型。
Therefore the code is valid so long as s
is const
. 因此,只要
s
是const
,代码就是有效的。
Rather than initialize with a size of 10, this initializes with a size of 1 with one element
10
而不是使用10的大小初始化,而是使用一个元素
10
初始化大小为1
First initializer-list are gready: 第一个初始化列表是gready:
§13.3.1.7 [over.match.list]/p1: §13.3.1.7[over.match.list] / p1:
When objects of non-aggregate class type
T
are list-initialized (8.5.4), overload resolution selects the constructor in two phases:当非聚合类类型
T
被列表初始化(8.5.4)时,重载决策分两个阶段选择构造函数:
- Initially, the candidate functions are the initializer-list constructors (8.5.4) of the class
T
and the argument list consists of the initializer list as a single argument.最初,候选函数是类
T
的初始化列表构造函数(8.5.4),参数列表由初始化列表作为单个参数组成。- If no viable initializer-list constructor is found, overload resolution is performed again, where the candidate functions are all the constructors of the class
T
and the argument list consists of the elements of the initializer list.如果找不到可行的初始化列表构造函数,则再次执行重载解析,其中候选函数是类
T
所有构造函数,参数列表由初始化列表的元素组成。If the initializer list has no elements and
T
has a default constructor, the first phase is omitted.如果初始化列表没有元素且
T
具有默认构造函数,则省略第一个阶段。 In copy-list-initialization, if anexplicit
constructor is chosen, the initialization is ill-formed.在copy-list-initialization中,如果选择了
explicit
构造函数,则初始化是错误的。
So the compiler will first try to create the vector using 因此编译器将首先尝试使用创建向量
vector( std::initializer_list<T> init, const Allocator& alloc = Allocator() );
As pointed out by user5389903 since you have a const std::size_t s
and its value is within the range of an int
it can convert {s}
into a std::initializer_list<int>
. 正如user5389903所指出的那样 ,因为你有一个
const std::size_t s
并且它的值在int
的范围内,所以它可以将{s}
转换为std::initializer_list<int>
。 now since we have a valid std::initializer_list
the std::initializer_list
constructor will be called. 既然我们有一个有效的
std::initializer_list
那么将调用std::initializer_list
构造函数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.