mirror of
https://github.com/CnTransGroup/EffectiveModernCppChinese.git
synced 2025-02-05 00:30:31 +08:00
修订翻译
This commit is contained in:
parent
ee8bef939a
commit
c69510e591
@ -71,7 +71,7 @@ private:
|
||||
... //没有“::type”
|
||||
};
|
||||
````
|
||||
对你来说,`MyAllocList<T>`(使用了模板别名声明的版本)可能看起来和`MyAllocList<T>::type`(使用`typedef`的版本)一样都应该依赖模板参数`T`,但是你不是编译器。当编译器处理`Widget`模板时遇到`MyAllocList<T>`(使用模板别名声明的版本),它们知道`MyAllocList<T>`是一个类型名,因为**MyAllocList**是一个别名模板:它**一定**是一个类型名。因此`MyAllocList<T>`就是一个**非依赖类型**(*non-dependent type*),就不需要也不允许使用`typename`修饰符。
|
||||
对你来说,`MyAllocList<T>`(使用了模板别名声明的版本)可能看起来和`MyAllocList<T>::type`(使用`typedef`的版本)一样都应该依赖模板参数`T`,但是你不是编译器。当编译器处理`Widget`模板时遇到`MyAllocList<T>`(使用模板别名声明的版本),它们知道`MyAllocList<T>`是一个类型名,因为`MyAllocList`是一个别名模板:它**一定**是一个类型名。因此`MyAllocList<T>`就是一个**非依赖类型**(*non-dependent type*),就不需要也不允许使用`typename`修饰符。
|
||||
|
||||
当编译器在`Widget`的模板中看到`MyAllocList<T>::type`(使用`typedef`的版本),它不能确定那是一个类型的名称。因为可能存在一个`MyAllocList`的它们没见到的特化版本,那个版本的`MyAllocList<T>::type`指代了一种不是类型的东西。那听起来很不可思议,但不要责备编译器穷尽考虑所有可能。因为人确实能写出这样的代码。
|
||||
|
||||
@ -105,7 +105,7 @@ std::add_lvalue_reference<T>::type //从T中产出T&
|
||||
|
||||
尽管写了一些,但我这里不是想给你一个关于*type traits*使用的教程。注意类型转换尾部的`::type`。如果你在一个模板内部将他们施加到类型形参上(实际代码中你也总是这么用),你也需要在它们前面加上`typename`。至于为什么要这么做是因为这些C++11的*type traits*是通过在`struct`内嵌套`typedef`来实现的。是的,它们使用类型同义词(译注:根据上下文指的是使用`typedef`的做法)技术实现,而正如我之前所说这比别名声明要差。
|
||||
|
||||
关于为什么这么实现是有历史原因的,但是我们跳过它(我认为太无聊了),因为标准委员会没有及时认识到别名声明是更好的选择,所以直到C++14它们才提供了使用别名声明的版本。这些别名声明有一个通用形式:对于C++11的类型转换`std::`transformation`<T>::type`在C++14中变成了`std::`transformation**`_t`**。举个例子或许更容易理解:
|
||||
关于为什么这么实现是有历史原因的,但是我们跳过它(我认为太无聊了),因为标准委员会没有及时认识到别名声明是更好的选择,所以直到C++14它们才提供了使用别名声明的版本。这些别名声明有一个通用形式:对于C++11的类型转换`std::`transformation`<T>::type`在C++14中变成了`std::`transformation`_t`。举个例子或许更容易理解:
|
||||
|
||||
````cpp
|
||||
std::remove_const<T>::type //C++11: const T → T
|
||||
|
Loading…
Reference in New Issue
Block a user