3

自动推导基础

auto 关键字的推导过程完全处于 compile-time,所以并不会影响程序性能。应该放心大胆的使用。

cppauto i = 1; // i will become int
auto l = 1LL; // l will become long long
auto d = 1.0; // d will become double
auto f = 1.0f; // f will become float

std::vector<int> ivec{1, 2, 3, 4, 5};
for (auto i : ivec) std::cout << i << " "; // 1 2 3 4 5

这样使用 auto 可能会要求你记住一些字面量的类型标识

  • 前置
    标识 含义 类型
    u Unicode 16 character char16_t
    U Unicode 32 character char32_t
    L wide character wchar_t
    u8 utf-8(string literals only) char

可能经常用 VS 和 Windows API 的人比较熟悉 L,用来标识宽字符。(不得不说,这一点,微软还是挺超前的)

  • 后置
    字面量 标识 类型
    整型 u / U unsigned
    整型 l / L long
    整型 ll / LL long long
    浮点 f / F float
    浮点 l / L long double

这些与 C 语言一脉相承,应该比较熟悉了。


特殊情况

cppauto str = "hello";

请问,str 是什么类型?最近才发现,很多初学者竟然想当然的认为strstd::string.(尤其是没有 C 语言基础的)

实际上,str 此时是 const char *.

所以当你对 str 进行 range for 的时候,就会傻眼。

cppfor (auto c : str) { // error! str 没有 begin() 和 end()
//...
}

上述情况应该如何避免?

cppauto& str = "hello";

请问,str是什么类型?

const char[6]. 这是一个数组了,那么 range for 当然没问题了。

还有别的方法吗?

当然,右值引用不是吃闲饭的:

cppauto&& str = "hello";

range for 照样没问题。请问 str 此刻是什么类型?

const char(&)[6].

这都是非常基础的内容,你都清楚吗?

另外补充一个:

cppauto il = {1, 2, 3, 4, 5, 6};

不要觉得 il 会是 std::array 或 普通数组,甚至是 std::vector. 它的类型应该是: std::initializer_list


什么时候该用 auto

  • 一种说法是:能用 auto 的地方都该用。(尤其是受到 python 等动态语言影响的人)。
  • 另一种说法:auto 会让代码变得不直观,在一个强类型的语言中,会搞得人莫名其妙。

经过一段时间的疯狂实践。我觉得上述两种观点都有失偏颇。

其实,开始我是支持第一种观点的,于是开始大量使用 auto, 直到有一天 review 自己的代码时。竟然发现很多变量完全看不出是什么类型。如:

cppauto foo = bla(); // 请问 foo 你能看出类型来吗?

这就傻眼了。违反了最基本的程序设计原则——“清晰易懂,方便扩展”,看都看迷糊了,扩展毛啊。

但有些情况,其实极大程度上的简化了程序,使之简洁明了:

cppauto foo = std::make_shared<Foo>(); // 一看就知道类型

for (auto iter = vec.cbegin(); iter != vec.cend(); ++iter) {} // 一看就知道类型

上述两种情况下,把 auto 扩展开来,会显得重复、冗长。

这两个例子,应该能够说明使用 auto 的那条 “金线” 在哪了。我们的目的不是为了用而用,而是尽可能的让自己的程序,易于维护,保持新鲜

故,不要滥用,不要避讳。


pezy
3.1k 声望332 粉丝

一个 C++ 程序员