Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Converting int to a size_t

I am wondering about the following warning of the clang compiler when I pass an integer to an std::initializer_list< size_t > :

non-constant-expression cannot be narrowed from type 'int' to 'unsigned long' in initializer list

Why can int be casted to a size_tbut an int not be passed to an std::initializer_list< size_t >, i.e.

int main()
{
  size_t s_t = 0;
  int    i   = 0;

  std::initializer_list<size_t> i_l = { i };            // warning
  s_t = i;                                              // no warning

  return 0;
}    
like image 896
abraham_hilbert Avatar asked Dec 20 '16 17:12

abraham_hilbert


People also ask

Can you compare int to size_t?

If you're going to compare an int type to size_t(or any other library type), you are doing a risky comparison because int is signed and size_t is unsigned, so one of them will be implicitly converted depending on your compiler/platform.

Is size_t better than int?

When writing C code you should always use size_t whenever dealing with memory ranges. The int type on the other hand is basically defined as the size of the (signed) integer value that the host machine can use to most efficiently perform integer arithmetic.

Is size_t a long or an int?

First, size_t normally means unsigned long , not int .

Can you cast size_t to int C?

Just use casting. You can safely convert size_t to int by checking its range before casting it. If it is outside the valid int range, you can't. Test against INT_MAX to ensure no possible signed integer overflow before casting it.


2 Answers

From [dcl.init.list]:

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 whose value after integral promotions will fit into the target type.

We are converting from int (which allows for negative values) to size_t (which does not), so this is a narrowing conversion. Narrowing conversions are ill-formed in list-initialization, which is what you're doing here:

std::initializer_list<size_t> i_l = { i };

However, narrowing conversions are fine elsewhere (as far as the standard is concerned):

s_t = i;

That's why the first line is ill-formed but the second is not.

like image 114
Barry Avatar answered Oct 04 '22 21:10

Barry


You have run afoul of [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 whose value after integral promotions will fit into the target type.

Since i is not a constant expression this counts as a narrowing conversion and narrowing conversions are not allowed in initializer list. If you were to use

std::initializer_list<std::size_t> i_l = { 0 };

Then it would not narrow even though 0 is an int since the compiler knows 0 can be represented in each type.

like image 22
NathanOliver Avatar answered Oct 04 '22 21:10

NathanOliver