在for循环中对std::array进行下标访问时的符号类型转换警告
据我理解,由于使用 for 循环来定义运行时控制流,element_declaration (e 在下面的示例中) 不应被视为常量表达式(尽管它复制了数组 x 的 constexpr 个元素)。为了在不产生符号转换警告的情况下对数组进行索引,我们必须使用 size_t 或者一个常量表达式。因此,为什么下面的程序在没有警告的情况下编译(对它来说 e 必须是一个常量表达式)?
#include <array>
struct Foo
{
enum X
{
a,
b,
c,
};
static constexpr std::array x { a, b, c };
};
int main()
{
std::array<int, 3> array {};
for (auto e: Foo::x)
array[e] = 1;
return 0;
}
然而,将数组赋值行改为(或在 [] 运算符内部进行任何算术运算)突然会触发警告:
array[e * 1] = 1;
warning: conversion to ‘s
td::array<int, 3>::size_type’ {aka ‘long unsigned int’} from ‘int’ may change the si
gn of the result [-Wsign-conversion]
20 | array[e * 1] = 1;
使用gcc 13.3.0(禁用扩展和优化)。
注:gcc和 clang都在使用 unsigned int 作为底层类型,但只有gcc会发出警告。msvc使用 int,但没有警告。
解决方案
对于没有固定底层类型的未作用域枚举,编译器将使用哪种底层类型是实现定义的。引自C++23标准(9.7.1枚举声明)
7对于底层类型未固定的枚举,底层类型是可以表示该枚举中定义的所有枚举值的整型类型。如果没有整型类型能表示所有的枚举值,枚举就是不合法的。实现定义使用哪种整型作为底层类型,除了底层类型不得大于int,除非某个枚举值不能适配int或 unsigned int。 如果枚举值列表为空,则底层类型就像枚举只有一个值为0 的枚举。
看起来在第一个程序中,编译器将枚举的底层类型设为无符号整数类型。
下面是一个演示程序(x86-64 gcc 16.1)。
#include <iostream>
#include <array>
#include <type_traits>
struct Foo
{
enum X
{
a,
b,
c,
};
static constexpr std::array x { a, b, c };
};
int main()
{
std::cout << std::boolalpha
<< std::is_same_v<std::underlying_type_t<Foo::X>, unsigned int>
<< '\n';
}
其输出为
true
因此,将无符号整数类型 unsigned int 的值转换为类型 size_t 没有问题。
在第二个代码片段中,使用有符号类型 int 在将负值转换为无符号整数类型 size_t 时可能会造成问题。因此,编译器可能会发出警告。
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。