自定义enum class范围for遍历是否符合C++标准?MyEnumClass()是何含义
连续枚举类范围for写法的语义与合法性说明
MyEnumClass()的实际语义
MyEnumClass()是对枚举类型MyEnumClass做值初始化生成的临时对象,由于枚举是值类型,值初始化后它的取值为0,正好对应你定义的第一个枚举项MyEnumClass::BEGIN。你把这个临时对象传给范围for作为遍历序列,完全符合C++语法要求。
写法合法性判定
这套实现是完全符合C++标准的合法代码,不存在未定义行为,原因如下:
- C++的范围for对自定义类型的支持规则本身就允许通过ADL(参数依赖查找)匹配自由函数
begin()/end(),你传入的临时枚举对象会触发ADL找到你定义的两个函数,分别返回遍历起点BEGIN和终点END。 - 枚举类型属于可重载运算符的类型范畴,你自定义的
operator++、operator*会在范围for展开的逻辑里被正常调用。 - 你做的枚举值和整数的转换操作全程合法:你的枚举底层类型是
int,枚举值连续从0到4(END对应值4),自增过程中产生的值都在枚举合法取值范围内,static_cast转换不存在未定义行为。
代码实际展开逻辑
你写的范围for循环会被编译器展开为等价的如下逻辑,和你观察到的运行结果完全匹配:
{ auto&& range = MyEnumClass(); auto it = begin(range); auto end_it = end(range); for (; it != end_it; ++it) { const auto& e = *it; std::cout << static_cast<int>(e) << std::endl; } }
循环从值0(BEGIN)开始,每次自增1,直到迭代器值等于4(END)时终止,正好遍历0/1/2/3四个值,对应你看到的输出。
注意:这个写法仅适用于枚举值严格连续的场景,如果枚举项中间存在跳值,或者自增后的值超出枚举的合法取值范围,会触发未定义行为。另外你当前
operator++里转unsigned的写法没有必要,直接转枚举的底层类型int更稳妥,可以兼容枚举项存在负值的场景。
内容的提问来源于stack exchange,提问作者Bertwim van Beest
相关产品推荐
相关产品推荐

