Effective Modern C++ 中文

Item 6: auto推导出非预期类型时请显示指定类型

Item 5 展示了一些使用auto定义变量的优势,但是auto在有些时候也会推导出一些我们不期望的类型。比如,一个函数通过传入一个Widget返回一个std::vector<bool>的类型,容器内的每一个bool值表示Widget的一个特征:

std::vector<bool> features(const Widget& w);

比如第5个bool值表示Widget是否是高优先属性,代码可以写成下面的形式:

Widget w;
...
bool highPriority = features(w)[5]; // w 是否是高优先属性?
...
processWidget(w, highPriority) // 根据是否是高优先性来处理 w
阅读更多 »Item 6: auto推导出非预期类型时请显示指定类型

Item 5: 推荐用 auto 定义类型

先观察下面两个例子:

int x;

是不是忘记了给 x 赋初值,因此现在它的值是不确定的。可能应该初始化成 0 吧。还是应该取决上下文吧。Get 到问题了吗?

我们再给局部变量的用迭代器解引用来进行初始化。

template <typename It>
void dwim(It b, It e)  //dwim 的算法是迭代 b 至 e 中所有的元素
{
  for (; b != e; ++b)
  {
    typename std::iterator_traits<It>::value_type currValue = *b;
    ...
  }
}

如果想知道迭代器值的类型,你要使用 “typename std::iterator_traits<It>::value_type” 来得到迭代器中值的类型,这非常考验你的记忆能力。

阅读更多 »Item 5: 推荐用 auto 定义类型

第二章 auto

从概念上看,auto 非常简单,其实它的细节有许多微妙之处。使用 auto 不但可以少敲键盘,而且可以防止手残而导致的错误或者低效的定义。此外,auto 定义的类型完全符合类型定义的规则。但是从程序员的角度来看的话,是错误的,因为程序员需要知道这里应该是什么类型,当然,退回到手动定义类型也是一种代替方法,但最好避免。

这个简短的介绍涵盖了 auto 的方方面面。

阅读更多 »第二章 auto

Item 4:查看推导类型

选择用什么工具查看类型推导结果取决于在什么开发阶段,需要获取什么样的信息。这里将探索三种阶段:编码阶段,编译阶段和运行阶段。

通过 IDE 编辑器运行信息

在使用 IDE 编码的过程中,当你把光标放在一些程序元素附近呢(比如,变量,参数,函数等等,IDE 时常会显示出程序元素的信息,例如,看下面的代码:

const int theAnswer = 42;

auto x = theAnswer;
auto y = &theAnswer;

IDE 会提示出类似 x 的推导类型是 int,b 的推导类型是 const int*。

阅读更多 »Item 4:查看推导类型

Item 3:理解 decltype

decltype 是一个奇怪的东西,给他传入一个变量名称或者表达式,它就能返回给i类型。通常情况下,它都能返回你想要知道的类型。然而,他的结果有时候会让你抓狂,到处找资料甚至在论坛上问别人。

不过说到这里,先不要害怕,我们首先从那些非常直观的 case 说起。与模版和 auto 相反,decltype 是通过你给出的名称或者表达式返回给你具体的类型:

const int i = 0;                      // decltype(i) 是 const int

bool f(const Widget& w);              // decltype(w) 是 const Widget&

struct Point {
  int x, y;                           // decltype(Point::x) 是 int
};                                    // decltype(Point::y) 是 int

Widget w;                             // decltype(w) 是 Widget

if (f(w)) ...                         // decltype(f(w)) 是 bool

template <typename T>                 // 这里是 std::vector 的简化版
class vector {
  ...
  T& operator[](std::size_t index);
  ...
};

vector<int> v;                        // decltype(v) 是 vector<int>
...
if (v[0] == 0) ...                    // decltype(v[0]) 是 int

看到了吗?非常直观,没有惊喜!

阅读更多 »Item 3:理解 decltype

Item 2:理解 auto 的推导

阅读完 Item 1 关于模板的推导,你基本上已经学会了推导 auto 所需要的知识,因为 auto 只有一个例外,这个在后面会讲到。模版类型推导包含了模版,函数以及函数的参数, 但 auto 并不处理以上任何一种情况,模版推导和 auto 之间的知识点为什么是一样的呢?

是的,就是这样。这里可以映射一套规则将模版推导和 auto 推导联系起来。从字面上来看,这好像是一个数学变换公式,将一个规则变换成另一个。

在 Item 1,用的是函数模版和函数调用来解释模版的推导:

template <typename T>
void f(ParamType param);      // 使用函数模版来推导

f(expr);                      // 使用函数调用来推导
阅读更多 »Item 2:理解 auto 的推导

Item 1: 理解模版类型推导

如果你正在使用一套复杂的系统,在没有明白其原理的情况下也能够正常使用,你可以认为这套系统设计的非常不错。按照这个思路,C++的模版类型推导绝对是巨大的成功。虽然这些使用模版的大部分程序员都很难描述出这些类型是怎么推导的,但是仍有数百万的程序员已经在使用模版来给函数传递参数并且得到正确的结果。

如果你也是其中之一,我将给你带来一个好消息和坏消息。好消息是C++的模版编程是现代C++编程中最酷炫的一个特性的基础:auto 关键字。如果你很喜欢C++98中模版类型推导,那么你也将同样喜欢 C++ 11 中 auto 的推导。而坏消息就是,auto 的推导规则看上去不如模版来的直观。因此,深刻理解 auto 所建立的模版类型推导十分的重要,它涵盖了你需要了解的知识点。

阅读更多 »Item 1: 理解模版类型推导

第一章 类型推导

C++98 只有一套类型推导规则,这套规则用于函数模版类型的推导。例如:

template <typename T>
void Print(T v) {
  std::cout << v;
}

Print(1);  // T 推导成 int
Print(1.0f);  // T 推导成 float

C++11 修改了一些规则,并且增加了两套新规则,一套用于 auto 的推导, 一套用于 decltype 的推导。然后,C++14 又扩展了 auto 和 decltype 的用法。类型推导的广泛应用使得编程人员不需要在拼命敲打各种类型的单词,并且增加了 C++ 程序的适应性,只要在源代码的一个地方修改,类型推导就可以自动传播到代码的其他相关部分。然后,这样的写法会让代码更加难以理解,毕竟编译器的类型推导可能与你想象的情况不太一样。

阅读更多 »第一章 类型推导