强类型枚举中作用域解析的原理 [英] Rationale behind scope resolution in strongly typed enumerations

查看:113
本文介绍了强类型枚举中作用域解析的原理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

无条件地在强类型枚举中需要显式范围解析的理由是什么?



N2347解释了与旧式枚举的区别,指定存储类型,并且没有在周围范围中注入名称(如在C ++ 03中,它具有C的遗产)。



换句话说,在C ++ 03中写入枚举E1 {a,b,c}; 类似于写

  const int a = 1; const int b = 2; const int c = 3; 

枚举E1类{a,b,c}; 在C ++ 11中类似于

 命名空间E1 {const int a = 1; const int b = 2; const int c = 3; } 

(不引入命名空间,并在每种情况下定义枚举类型)。



现在,我通常不明白哪里有歧义,假设有一个像下面的代码(不会编译):

 枚举类E1 {a,b,c}; 
枚举类E2 {a,b,c}; //允许现在

void foo(E1 e){...}
void bar(E2 e){...}
void baz(int e){。 ..}

foo(a); // not ambigious:E1 expected,nothing but E1 :: a possible
bar(a); // not ambigious:E2 expected,nothing but E2 :: a possible
baz(a); // not ambigious:illegal - no name`a` in global scope

E1 x = a; // not ambigious:E1 expected,nothing but E1 :: a possible

范围解决在某些情况下指出发生了什么,但我不明白为什么C ++ 11需要显式范围解析,即使没有可能的方式解释代码以另一种方式。



在我看来,期望例如 void foo(E1 e); 的含义更像是 void foo(using enum E1; E1 e); (我的语法当然完全错了,但你得到了想法。)



在N2347中的 Color Alert 的经典示例,有一个红色警报颜色红色,它们也可以是不同的数字常量。在没有强类型保证的情况下,可以想到的是,当真正想要例如使用警告数字常数时,结束使用警报数字常数。在显示屏上设置红色。或者,对于整数转换和一个松散的函数声明,可以想象有人最终使用像 yellow | red 来获取橙色。


$

解决方案


p> foo(a); // not ambigious:E1 expected,nothing but E1 :: a possible


表达式的类型必须是已知的。由于 a 作为独立表达式的使用是不明确的,因此在任何地方使用 a 是不明确的。 / p>

您不希望表达式根据其使用的上下文更改其含义。 1 + 1 总是意味着同样的事情。 1 + t 总是意味着同样的事情,如果你使用相同的 t 。类似地, a 应该总是意味着相同的事情,无论它在哪里使用。



允许基于其使用的上下文的源类型的推导是均匀初始化。并且标准明确地声明braced-init-list是不是表达式。 a 是一个表达式,因此它遵循表达式规则。


What is the rationale behind unconditionally requiring explicit scope resolution in strongly typed enumerations?

N2347 explains the difference to old-fashion enumerations which are absence of implicit conversion, ability to specify storage type, and no injection of names in the surrounding scope (as in C++03, which has that as a heritage of C).

In other words, writing enum E1 { a, b, c}; as in C++03 is similar to writing

const int a = 1; const int b = 2; const int c = 3;

whereas enum E1 class { a, b, c}; as in C++11 is much more similar to something like

namespace E1 { const int a = 1; const int b = 2; const int c = 3; }

(without introducing a namespace, and with defining an enum type in either case).

Now, I generally don't understand where there is an ambiguity, assuming one has for example code like the following (which won't compile):

enum class E1 { a, b, c };
enum class E2 { a, b, c }; // allowed now

void foo(E1 e) { ... }
void bar(E2 e) { ... }
void baz(int e) { ... }

foo(a);   // not ambigious: E1 expected, nothing but E1::a possible
bar(a);   // not ambigious: E2 expected, nothing but E2::a possible
baz(a);   // not ambigious: illegal - no name `a` in global scope

E1 x = a; // not ambigious: E1 expected, nothing but E1::a possible

I welcome (optional) explicit scope resolution in some cases to point out what's going on, but I do not understand why C++11 requires explicit scope resolution, even when there is no possible way of interpreting code in another way.

It would in my opinion be reasonable to expect that for example void foo(E1 e); has a meaning much more like void foo(using enum E1; E1 e); (my syntax is of course totally wrong, but you get the idea).

Taking the "classic" example of Color and Alertthat is also in N2347, one has red alert, and the color red, which may be different numeric constants, too. Without strong type guarantees, it is conceivable that one ends up using the alert numeric constant when one really wants to e.g. set a red color on a display. Or, with integer conversions and a lax function declaration, it is conceivable that someone ends up using something like yellow|red to get orange.

None of that is possible, so what exactly are we defending against?

解决方案

foo(a); // not ambigious: E1 expected, nothing but E1::a possible

The type of the expression must be known. And since the use of a as a free-standing expression is ambiguous, the use of a anywhere is ambiguous.

You don't want expressions to change their meaning depending on the context they're used in. 1 + 1 always means the same thing. 1 + t always means the same thing if you use the same t. Similarly, a should always mean the same thing no matter where it is used.

The only thing in C++ that allow for the deduction of the source type based on the context in which it is used is uniform initialization. And the standard explicitly states that a "braced-init-list" is not an expression. a is an expression, so it follows the expression rules.

这篇关于强类型枚举中作用域解析的原理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆