Strange behavior of narrowing in context of initializer lists

795 views Asked by At

Does someone knows why this compiles without warnings

int main()
{
  const int i = 1024;
  std::initializer_list<size_t> i_l = { i }; // no warning

  return 0;
}

but does not

int main()
{
  const int i = pow(2,10);
  std::initializer_list<size_t> i_l = { i }; // warning

  return 0;
}

Warning:

non-constant-expression cannot be narrowed from type 'int' to 'unsigned long' in initializer list [-Wc++11-narrowing]
      std::initializer_list<size_t> i_l = { i }; i_l = i_l; // warning
1

There are 1 answers

2
Barry On BEST ANSWER

Quoting the same section as from your previous question, [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.

What counts as a constant expression? That is defined in [expr.const]:

A conditional-expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine (1.9), would evaluate one of the following expressions: [...]
— an invocation of a function other than a constexpr constructor for a literal class, a constexpr function, or an implicit invocation of a trivial destructor
— [...]
— an lvalue-to-rvalue conversion (4.1) unless it is applied to a non-volatile glvalue of integral or enumeration type that refers to a complete non-volatile const object with a preceding initialization, initialized with a constant expression
— [...]

So, i is a constant expression in const int i = 1024; because i is a non-volatile const object of integral type initialized with a constant expression (1024). But in the second example, pow() isn't a constant expression because it's an invocation of a non-constexpr function.

Hence, the first example doesn't count as narrowing but the second does. You can think of it as the compiler knows that 1024 is fine, but doesn't know that pow(2, 10) is.