Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementation-defined narrowing conversions?

C++11 formalized the notion of a narrowing conversion, and disallowed using one at the top level in list-initialization.

I am wondering whether, given two types T and U, it is possible for it to be implementation-defined whether a conversion from T to U is narrowing. According to my reading of the standard, this is the case. Here is my reasoning:

  • According to dcl.init.list (8.5.4) paragraph 7, one way a conversion can be narrowing is if it's 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".
  • Consider an implicit conversion from unsigned int to long.
  • Regarding the relative sizes of int and long, C++ requires only that sizeof(int) <= sizeof(long).
  • Consider an implementation A, where sizeof(int) == sizeof(long). On this implementation, long cannot represent all the values of unsigned int, so the conversion would be narrowing.
  • Consider an implementation B, where sizeof(int) < sizeof(long). On this implementation, long can represent all the values of unsigned int, so the conversion would not be narrowing.

Am I correct in my analysis that it can be implementation-defined whether a conversion is narrowing? Is this desirable?

like image 703
HighCommander4 Avatar asked Nov 19 '12 10:11

HighCommander4


1 Answers

I would indeed prefer the "narrowing conversion" to be defined on the types itself. In a way so that int i{long(non_constant_expression)} is never allowed to compile. The simple reason is: Either you don't need the long range, then you should use int in the first place, or you really want the "cut", which seems like a rare enough case for me to require an explicit type conversion or a cast. To answer the first question: It is implementation defined.

But to be honest, I almost never use this raw types, just size_t, int32_t, uint16_t etc., and this solves the problem automatically. (uint16_t {uint8_t()} is always narrowing, uint16_t{uint16_t()} never.) One just has to thoughtfully convert size_t into something else, but that is always the case.

like image 98
cooky451 Avatar answered Oct 13 '22 20:10

cooky451