转向现代C++——优先选用限定作用域的枚举型别,而非不限作用域的枚举型别
文章目录优先选用限定作用域的枚举型别而非不限作用域的枚举型别名字空间污染强类型安全与隐式转换前置声明特例什么时候不限作用域的 enum 更好现代 C 的替代方案C17 结构化绑定优先选用限定作用域的枚举型别而非不限作用域的枚举型别在 C98 中我们使用的 enum 是不限作用域的unscoped enum而 C11 引入了通过 enum class 声明的限定作用域的枚举scoped enum。绝大多数情况下选择 enum class。它能帮你屏蔽掉大量由于隐式类型转换和命名冲突导致的低级 Bug。名字空间污染不限作用域的枚举enum中定义的名字会直接泄漏到该枚举所在的作用域中。这意味着你不能在同一个作用域内定义同名的枚举常量。enumColor{black,white,red};// 编译错误black 已经在这个作用域被定义过了// enum class Astronomy { black, white, red };autowhitefalse;// 编译错误white 已被用作枚举常量enum class 的名字只在枚举内部可见必须通过作用域解析运算符::来访问解决了命名冲突。enumclassColor{black,white,red};enumclassLight{google,white,baidu};// white 不会冲突Color cColor::black;// 必须加上 Color::Light lLight::white;// 必须加上 Light::autowhitefalse;//此时的 white 是一个独立的变量强类型安全与隐式转换不限作用域的枚举会极其隐式地转换为整型甚至浮点型这经常导致不合逻辑的代码能够通过编译。而 enum class 是强类型的绝不隐式转换。enumColor{black,white,red};Color cred;// 荒谬的比较颜色竟然可以和数字、浮点数直接比大小if(c14.5){// 编译通过red 被隐式转换成了整数 2autoxc*10;// 编译通过允许算术运算}enumclassColor{black,white,red};Color cColor::red;// if (c 14.5) { } // 编译错误不能将 Color 与 double 进行比较// if (c 2) { } // 编译错误不能将 Color 与 int 进行比较// 如果真的需要转换必须进行显式类型转换static_castif(static_castint(c)2){// 显式转换安全且意图明确}前置声明在 C 中能够前置声明一个类型可以减少头文件包含从而加快编译速度。:::info传统 enum通常不能前置声明。因为编译器需要知道枚举的最大值以此来决定底层用多大的整数类型char、int 还是 short来存储它。::::::successenum class天生支持前置声明。因为它的默认底层类型underlying type是固定的标准规定默认为 int。:::// 头文件 Widget.h enum class Status; // 完美支持前置声明不需要知道具体有哪些枚举值 class Widget { Status s; // 编译器知道 Status 默认是 int 大小4字节可以确定 Widget 大小 }; // 实现文件 Widget.cpp enum class Status { Good, Failed, Unknown }; // 在这里才给出具体定义:::color4**补充说明C11 也允许传统的 enum 进行前置声明但你必须显式指定底层类型**如 enum Color: uint8_t;。而enum class 不需要显式指定默认就是 int。:::特例什么时候不限作用域的 enum 更好**当我们需要使用std::tuple并通过语义化的名字去获取里面的元素时传统 ****enum的隐式转换反而成了一种“便利”。**#includetuple#includestringusingUserInfostd::tuplestd::string,// 姓名std::string,// 邮箱std::size_t;// 声望值// 使用传统的 unscoped enumenumUserFields{uName,uEmail,uRep};voidprocessUser(){UserInfou(Alice,aliceemail.com,99);// 隐式转换为了 std::size_t语法非常自然autonamestd::getuName(u);}enumclassUserFields{uName,uEmail,uRep};voidprocessUser(){UserInfou(Alice,aliceemail.com,99);// 极其恶心、冗长的语法必须 static_castautonamestd::getstatic_caststd::size_t(UserFields::uName)(u);}现代 C 的替代方案C17 结构化绑定在现代 CC17 及以后中即使是上述特例我们也不再依赖传统 enum 了因为我们有了结构化绑定它比上面两种方法都更优雅voidprocessUser(){UserInfou(Alice,aliceemail.com,99);// 直接解包连枚举都不需要定义了auto[name,email,rep]u;}
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2626463.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!