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

时间:2016-12-20 23:57:25

标签: c++ initializer-list narrowing

有人知道为什么这会在没有警告的情况下编译

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

1 个答案:

答案 0 :(得分:4)

引用与previous question,[dcl.init.list]相同的部分:

  

缩小转换是一种隐式转换[...] - 从整数类型或无范围枚举类型到不能表示原始类型的所有值的整数类型,除非源是常量表达式积分促销后的值将适合目标类型

什么算作常数表达式?这在[expr.const]中定义:

  

条件表达式e是核心常量表达式,除非根据抽象机器(1.9)的规则评估e将评估以下表达式之一:[...]
   - 为文字类,constexpr函数或简单析构函数的隐式调用调用除constexpr构造函数之外的函数    - [...]
   - 左值到右值的转换(4.1),除非它应用于整数或枚举类型的非volatile glvalue,它引用一个完整的非volatile const对象在初始化之前,用常量表达式初始化
   - [...]

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

因此,第一个例子不算是缩小,而第二个例子。您可以将其视为编译器知道 1024是好的,但不知道pow(2,10)是。