C++11: "narrowing conversion inside { }"模量

C++11: "narrowing conversion inside { }" with modulus

本文关键字:inside 模量 conversion narrowing C++11      更新时间:2023-10-16

我尝试在启用gccC++11的情况下编译以下代码:

unsigned int id = 100;
unsigned char array[] = { id % 3, id % 5 };

我收到以下警告:

{ } 中将"(id % 3u)"从"无符号 int"到"无符号字符"的转换范围缩小 [-缩小]

在线观看演示

有没有办法帮助编译器发现 id % 3 的结果适合无符号字符

在这种特定情况下,使用 const 或 constexpr id将解决问题:

constexpr unsigned int id = 100;

因为有一个例外,即您有一个常量表达式,其转换后的结果将适合目标类型。

在更一般的情况下,您还可以使用 static_cast 将结果转换为无符号字符:

{ static_cast<unsigned char>( id % 3), static_cast<unsigned char>( id % 5) }
  ^^^^^^^^^^^                          ^^^^^^^^^^^

我们可以在 List-initialization 8.5.4草案C++标准部分中找到常量表达式和缩小转换的例外,其中说:

缩小转换是隐式转换

并包括以下项目符号(强调我的):

    从整数类型
  • 或无作用域枚举类型到不能表示原始类型的所有值的整数类型,除了 其中源是一个常量表达式,其值在积分之后 促销活动将适合目标类型

请注意,由于缺陷报告 1449,措辞从最初的 C++11 标准草案更改为我上面引用的内容。

几乎所有数学运算都将它们的参数转换为int,这是一个C++怪癖。

下面是非加宽%mod%运算符的草图:

template<class T, class U,class=void> struct smallest{using type=T;};
template<class T, class U>
struct smallest<T,U,std::enable_if_t<(sizeof(T)>sizeof(U))>>{using type=U;};
template<class T,class U>using smallest_t=typename smallest<T,U>::type;
constexpr struct mod_t {} mod;
template<class LHS>struct half_mod { LHS lhs; };
template<class LHS>
constexpr half_mod<std::decay_t<LHS>> operator%( LHS&& lhs, mod_t ) { return {std::forward<LHS>(lhs)}; }
template<class LHS, class RHS>
constexpr smallest_t<LHS, std::decay_t<RHS>> operator%( half_mod<LHS>&& lhs, RHS&& rhs ) {
  return std::move(lhs.lhs) % std::forward<RHS>(rhs);
}

mod b 的结果应该是两种类型中最小的,因为它不能更大。 可能应该为已签名/未签名的人做一些工作,但我会平底船并采取第一个。

所以id %mod% 3最终被char.

您可以使用

unsigned char array[] = {
    static_cast<unsigned char>(id % 3),
    static_cast<unsigned char>(id % 5)
};

由于id是一个unsigned intid % 3的类型也将是一个unsigned int

您的编译器正在警告您,unsigned char(标准为 8 位)可能太小而无法接收unsigned int(标准至少为 16 位)。

当然,在这种特殊情况下,您知道得更好。使用 static_cast<unsigned char>(id % ...) 告诉编译器缩小转换是安全的。