c++11 auto

auto现在成了一个类型的占位符,通知编译器去根据初始化代码推断所声明变量的真实类型。

使用auto会拖慢c++效率吗?完全不会,因为在编译阶段编译器已经帮程序员推导好了变量的类型。
使用auto会拖累C++编译效率吗?完全不会,因为在auto出现之前C++需要先推导等号右侧表达式的类型,然后检查它与变量的类型是否可以转换(兼容转换、向下类型转换和自定义类型转换)。auto出现之后,C++在推导出等号右侧表达式的类型之后,直接指定给变量。

一 使用auto注意事项

  1. auto 定义变量时==必须同时初始化==(类似引用)
    因为是根据变量的值进行类型推导
#include <iostream>
int main()
{
  auto x; // error
  auto y = 10; // ok
}

编译错误

➜ main make lan=c++ ver=c++11
g++ main.cpp -std=c++11
main.cpp:4:8: error: declaration of variable 'x' with type 'auto' requires an initializer
auto x;
^
1 error generated.
make: *** [all] Error 1
➜ main
requires an initializer auto x;

  1. 不允许使用auto定义==函数参数==
#include <iostream>

void func(auto x)
{}

int main()
{}

编译错误

➜ main make lan=c++ ver=c++11
g++ main.cpp -std=c++11
main.cpp:3:11: error: 'auto' not allowed in function prototype
void func(auto x)
^~~~
1 error generated.
make: *** [all] Error 1
➜ main

  1. 不允许使用auto定义==struct/class的成员变量==
#include <iostream>

struct animal
{
  int age;
  auto name; // error: 无法确定最终外层struct的占用长度
};

int main()
{}

编译错误

➜ main make lan=c++ ver=c++11
g++ main.cpp -std=c++11
main.cpp:6:3: error: 'auto' not allowed in non-static struct member
auto name;
^~~~
1 error generated.
make: *** [all] Error 1
➜ main

  1. 不允许使用auto定义==数组==
#include <iostream>

int main()
{
  auto arr[5]; // error: 同样无法确定数组的总占用长度
}

编译错误

➜ main make lan=c++ ver=c++11
g++ main.cpp -std=c++11
main.cpp:5:11: error: 'arr' declared as array of 'auto'
auto arr[5];
^
1 error generated.
make: *** [all] Error 1
➜ main

  1. 不允许使用auto作为==模板参数==传递
#include <iostream>
#include <vector>

int main()
{
  std::vector<int> v1; // ok
  std::vector<auto> v2; // error
}

编译错误

➜ main make lan=c++ ver=c++11
g++ main.cpp -std=c++11
main.cpp:7:15: error: 'auto' not allowed in template argument
std::vector<auto> v2; // error
^~~~
main.cpp:7:21: error: C++ requires a type specifier for all declarations
std::vector<auto> v2; // error
^
2 errors generated.
make: *** [all] Error 1
➜ main

二 函数返回值推导

函数返回类型自动推导
函数返回类型自动推导是指C++11以及C++14中不直接给出函数返回类型,而是使用类型指示符来指示返回类型甚至彻底省略返回类型并最终由编译器来推导返回类型的语言特性。
函数返回类型自动推导原则如下:

(1)当函数体内不包含任何返回值时,该函数的返回类型为void。
当函数体内只包含一句带返回值的return语句时,该函数的返回类型等同于该返回值的类型。
(2)当函数体内包含多个带返回值的return语句时,该函数的返回类型由这些返回值的类型共同决定,所有返回值的类型必须相同。
函数体内的返回值可以递归调用自身,但这类无法由编译器自动推导类型的返回值,必须发生在可以由编译器自动推导类型的非递归调用的返回值之后。
(3)在lambda表达式中省略返回类型
(4)当lambda表达式中省略返回类型时,lambda表达式的返回类型由编译器根据返回值以及模板参数推导规则进行自动推导。

声明函数时使用auto指示符来指示返回类型
当函数的返回类型包含auto指示符并且函数的后置返回类型被省略时,函数的返回类型由编译器根据返回值以及模板参数推导规则进行自动推导。

声明函数时使用decltype(auto)指示符来指示返回类型
当函数的返回类型为decltype(auto)指示符时,函数的返回类型由编译器根据返回值以及decltype推导规则进行自动推导。

#include <iostream>
#include <string>
#include <typeinfo>
 
template<typename T>  
T f();
 
auto f2(int n)
{
    return n + 1;
}
auto f3(bool b)
{
    if(b) return 1.0;
    else return 2.0;
}
auto f4(int n)
{
    if(n == 0) return 1;
    else return n * f4(n - 1);
}
struct S
{
    int n1, n2;
    decltype(auto) f6(bool b)
    {
        if(b) return (n1);
        else return (n2);
    }
};
 
int main()
{
    auto f1 = [](int a){std::cout << a;};
    auto f5 = [](auto a, auto b){return a + b;};
    f<decltype(f1(1))>();
    f<decltype(f2(1))>();
    f<decltype(f3(false))>();
    f<decltype(f4(3))>();
    f<decltype(f5(1.0f, 3.0f))>();
    S s;
    f<decltype(s.f6(false))>();
}
main.cpp:(.text.startup+0x5): undefined reference to `void f<void>()'
main.cpp:(.text.startup+0xa): undefined reference to `int f<int>()'
main.cpp:(.text.startup+0xf): undefined reference to `double f<double>()'
main.cpp:(.text.startup+0x14): undefined reference to `int f<int>()'
main.cpp:(.text.startup+0x19): undefined reference to `float f<float>()'
main.cpp:(.text.startup+0x1e): undefined reference to `int& f<int&>()'

这段代码使用了一种特殊技巧来查看编译器所实际推导出的函数返回类型。代码中定义了一个未被实现的函数模板f,该函数模板有一个类型参数T。如果用某个类型T来调用该函数模板,编译器就会因找不到函数模板的定义而输出”T f<T>()未被定义“的出错信息。也就是说,利用该函数模板,我们便可以在编译器所输出的出错信息中检查模板参数T的实际类型。在main函数内,我们充分利用了这一个技巧,通过利用函数返回类型调用该函数模板来让编译器输出相应的类型。
从出错信息中可以得知:

lambda表达式f1的返回类型被推导为void。

理由:lambda表达式的函数体内没有任何返回值。

函数f2的返回类型被推导为int。

理由:函数体内只包含一个return语句,返回值n+1类型为int。

函数f3的返回类型被推导为double。

理由:函数体内包含两个return语句,返回值1.0以及2.0类型都是double。

函数f4的返回类型被推导为int。

理由:函数体内包含两个return语句,其中第二个返回值递归调用自身,无法推导,而第一个返回值1类型为int。

lambda表达式f5的返回类型被推导为表达式a+b的类型。当 a=1.0f, b=3.0f 时,f5的返回类型为表达式 1.0f + 3.0f 的类型,即float。

理由:函数体内只包含一个return语句,返回值a+b类型取决于泛型参数a以及b的类型。

函数f6的返回类型被推导为int&。

理由:函数体内包含两个return语句,将返回值(n1)以及(n2)代入decltype(auto)结果类型都是int&。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容