【问题标题】:Using Integer Literals in C++ Initializer List在 C++ 初始值设定项列表中使用整数文字
【发布时间】:2020-02-23 23:23:18
【问题描述】:

我正在尝试了解 {} 初始化程序语法的全部功能。

我用g++编译了如下代码:

int i = 0;                /* OK */

short int si2 {i};        /* Warning: Narrowing Conversion inside {...} */

char myChar {127ULL};     /* OK */

char myChar2 {128ULL};    /* Warning: Narrowing Conversion inside {...} */

我对si2初始化警告的理解如下。在我的系统上: - short int 是 2 个字节 - int 是 4 个字节

因为初始化器的大小(以字节为单位)是 LHS 的两倍,这构成了缩小,因此会给出编译器警告。

但是对于 myCharmyChar2,这两个初始化器具有相同的数据类型:unsigned long long int。我相信 myChar2 的初始化已经发生,因为初始化器的值对于 char 数据类型来说太大了。

相同的规则似乎不适用于这两种情况: 1. 由于初始化器数据类型对于已初始化变量而言太大而失败 2. 初始化变量的值太大导致失败(虽然这里可以接受RHS数据类型)

我的理解是否正确 - 如果参数是整数文字,初始化列表的行为是否不同?

【问题讨论】:

  • 如果你改用constexpr int i = 0; 会发生什么?它应该使静态确定初始化是否有问题变得更加简单。

标签: c++ initialization initializer-list


【解决方案1】:

记住这件事。

当与内置类型的变量一起使用时,这种形式的初始化有一个 重要属性:如果初始化器可能导致信息丢失,编译器不会让我们列出内置类型的初始化变量:

    long double ld = 5.14159265;
    int a{ld}, b = {ld}; // error: narrowing conversion required
    int c(ld), d = ld; // ok: but value will be truncated

编译器拒绝 a 和 b 的初始化,因为使用 long double 来 初始化一个 int 可能会丢失数据。至少,ld 的小数部分将是 截断。此外,ld 中的整数部分可能太大而无法放入 int 中。

现在到最后两部分。 您定义了签名类型的 char。它可以保存从 -128 到 127 的值。但是您尝试分配 128,这就是您从编译器收到的警告。

【讨论】:

  • 您好,感谢您的回复。如果初始化列表防止信息丢失,为什么char myChar {127ULL}; 不给出警告?不要更改有符号性,并且将数据类型从 Unsigned Long Long Int 缩小到 Signed Char 算作信息丢失?
  • @thatmarkdude 理想情况下,我们应该始终尝试防止任何类型的数据丢失。所以列表通过防止来完成它们的工作,但有时我们知道我们的操作会丢失数据,但我们仍然不关心它,并且在这种情况下使用括号。
【解决方案2】:

您的编译器默认情况下似乎认为char 类型类似于signed char 类型。

在这些声明中

char myChar {127ULL};     /* OK */

char myChar2 {128ULL};

初始化器具有正值,并且正值128 不能在signed char 类型的对象中表示。

signed char 类型可以表示的最大正值是127。也就是说值的范围是[-128, 127]

因此编译器发出警告。

为此声明

short int si2 {i}; 

编译器发出警告,因为初始化器不是编译时常量。

如果你会写

const int i = 0;

然后警告消失。

【讨论】:

  • 您好,感谢您的回复。好的,我现在看到如果初始化值在编译时已知,并且在初始化变量的允许范围内,则不会发出警告。如果在编译时未知,并且数据类型较大,则会发出警告。
猜你喜欢
  • 2019-04-16
  • 2020-07-31
  • 1970-01-01
  • 2012-12-24
  • 2016-01-22
  • 1970-01-01
  • 1970-01-01
  • 2013-06-12
  • 1970-01-01
相关资源
最近更新 更多