update item10

This commit is contained in:
racaljk 2017-12-11 19:02:48 +08:00
parent 9653a94bd5
commit 8c875b1a1e
3 changed files with 20706 additions and 1 deletions

View File

@ -34,3 +34,133 @@ if (c < 14.5) { // Color与double比较 (!)
}
```
在**enum**后面写一个**class**就可以将非限域枚举转换为限域枚举,接下来就是完全不同的故事展开了。
现在不存在任何隐式的转换可以将限域枚举中的枚举量转化为任何其他类型。
```cpp
enum class Color { black, white, red }; // Color现在是限域枚举
Color c = Color::red; // 和之前一样,只是
… // 多了一个域修饰符
if (c < 14.5) { // 错误不能比较
// Color和double
auto factors = // 错误! 不能向参数为std::size_t的函数
primeFactors(c); // 传递Color参数
}
```
如果你真的很想执行Color到其他类型的转换和平常一样使用正确的类型转换运算符扭曲类型系统
```cpp
if (static_cast<double>(c) < 14.5) { // 奇怪的代码但是
// 有效
auto factors = // suspect, but
primeFactors(static_cast<std::size_t>(c)); // 能通过编译
}
```
看来比起非限域枚举而言限域枚举有第三个好处,因为限域枚举可以前声明。比如,它们可以不指定枚举量直接前向声明:
```cpp
enum Color; // 错误!
enum class Color; // 没问题
```
这是一个误导。在C++11中非限域枚举也可以被前向声明但是只有在做一些其他工作后才能实现。这些工作来源于一个事实
在C++中所有的枚举都有一个由编译器决定的基础整型类型。对于非限域枚举比如Color
```cpp
enum Color { black, white, red };
```
编译器可能选择**char**作为基础类型,因为这里只需要表示三个值。然而,有些枚举中的枚举值范围可能会大些,比如:
```cpp
enum Status { good = 0,
failed = 1,
incomplete = 100,
corrupt = 200,
indeterminate = 0xFFFFFFFF
};
```
这里值的范围从**0**到**0xFFFFFFFF**。除了在不寻常的机器上(比如一个**char**至少有32bits的那种编译器都会选择一个比**char**大的整型类型来表示**Status**。
To make efficient use of memory, compilers often want to choose the smallest underlying
type for an enum thats sufficient to represent its range of enumerator values. In
some cases, compilers will optimize for speed instead of size, and in that case, they
may not choose the smallest permissible underlying type, but they certainly want to
be able to optimize for size. To make that possible, C++98 supports only enum definitions
(where all enumerators are listed); enum declarations are not allowed. That
makes it possible for compilers to select an underlying type for each enum prior to the
enum being used.
But the inability to forward-declare enums has drawbacks. The most notable is probably
the increase in compilation dependencies. Consider again the Status enum:
```cpp
enum Status { good = 0,
failed = 1,
incomplete = 100,
corrupt = 200,
indeterminate = 0xFFFFFFFF
};
```
This is the kind of enum thats likely to be used throughout a system, hence included
in a header file that every part of the system is dependent on. If a new status value is
then introduced,
```cpp
enum Status { good = 0,
failed = 1,
incomplete = 100,
corrupt = 200,
audited = 500,
indeterminate = 0xFFFFFFFF
};
```
its likely that the entire system will have to be recompiled, even if only a single subsystem—
possibly only a single function!—uses the new enumerator. This is the kind
of thing that people hate. And its the kind of thing that the ability to forward-declare
enums in C++11 eliminates. For example, heres a perfectly valid declaration of a
scoped enum and a function that takes one as a parameter:
```cpp
enum class Status; // forward declaration
void continueProcessing(Status s); // use of fwd-declared enum
```
The header containing these declarations requires no recompilation if Statuss
definition is revised. Furthermore, if Status is modified (e.g., to add the audited
enumerator), but continueProcessings behavior is unaffected (e.g., becausecontinueProcessing doesnt use audited), continueProcessings implementation
need not be recompiled, either.
But if compilers need to know the size of an enum before its used, how can C++11s
enums get away with forward declarations when C++98s enums cant? The answer is
simple: the underlying type for a scoped enum is always known, and for unscoped
enums, you can specify it.
By default, the underlying type for scoped enums is int:
```cpp
enum class Status; // underlying type is int
```
If the default doesnt suit you, you can override it:
```cpp
enum class Status: std::uint32_t; // underlying type for
// Status is std::uint32_t
// (from <cstdint>)
```
Either way, compilers know the size of the enumerators in a scoped enum.
To specify the underlying type for an unscoped enum, you do the same thing as for a
scoped enum, and the result may be forward-declared:
```cpp
enum Color: std::uint8_t; // fwd decl for unscoped enum;
// underlying type is
// std::uint8_t
```
Underlying type specifications can also go on an enums definition:
```cpp
enum class Status: std::uint32_t { good = 0,
failed = 1,
incomplete = 100,
corrupt = 200,
audited = 500,
indeterminate = 0xFFFFFFFF
};
```
In view of the fact that scoped enums avoid namespace pollution and arent susceptible
to nonsensical implicit type conversions, it may surprise you to hear that theres
at least one situation where unscoped enums may be useful. Thats when referring to
fields within C++11s std::tuples. For example, suppose we have a tuple holding
values for the name, email address, and reputation value for a user at a social networking
website:
```cpp
using UserInfo = // type alias; see Item 9
std::tuple<std::string, // name
std::string, // email
std::size_t> ; // reputation
```

View File

@ -2,7 +2,7 @@
![bookLogo](http://p1.bpimg.com/567571/bc7c228ba08fae01.png)
> ! 2017.10开始更新<br>
> ! 我没有版权,我没有版权,我没有版权侵权请告知1948638989@qq.com<br>
> ! 我没有版权,我没有版权,我没有版权<br>
> 本书要求读者具有C++基础<br>
> !未翻译的条款名称现在直译,翻译时可能适当修改<br>
> 条款后的revised表明该条款已经经过初步修订<br>

File diff suppressed because one or more lines are too long