在初始化列表的上下文中缩小的奇怪行为

Strange behavior of narrowing in context of initializer lists

有人知道为什么编译时没有警告

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

  return 0;
}

但不会

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

  return 0;
}

警告:

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

引用与您的 相同的部分,[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.

什么算常量表达式?在 [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
— [...]

所以,iconst int i = 1024;中的一个常量表达式,因为i是一个非volatileconst整型对象,用常量初始化表达式(1024)。但在第二个示例中,pow() 不是常量表达式,因为它是对非 constexpr 函数的调用。

因此,第一个示例不算缩小范围,但第二个示例算作缩小范围。您可以将其视为编译器 知道 1024 可以,但不知道 pow(2, 10) 可以。