auto关键字的含义是什么?

212
据我所了解,auto一直是一个奇怪的存储类别说明符,没有任何实际用途。
然而,我尝试了一下auto的用法,它会根据我赋给它的值来确定类型!使用auto可以让涉及迭代器和其他许多东西的代码更容易编写。
这个关键字从什么时候开始可以使用?这是Visual C++的扩展吗?

31
不是魔法,而是新技术(哦不,这个双关语有点糟)。异步编程现在是未来的趋势(吸氧声)。 - sehe
6
以下是关于auto关键字的参考链接:http://en.cppreference.com/w/cpp/language/auto。 - andyqee
8个回答

221

auto是C++从C语言中“继承”过来的关键字,它在C语言中存在了很长时间,但几乎从未被使用,因为只有两种可能的情况:要么不允许,要么默认就是如此。

C++11中新增使用auto表示推断类型。

同时,auto x = initializer会从initializer的类型中推断出x的类型,这与函数模板的模板类型推导方式相同。考虑下面的函数模板:

template<class T>
int whatever(T t) { 
    // point A
};

在A点,根据传递给whatever参数的值,已经为T分配了一种类型。当你执行auto x = initializer;时,同样的类型推断被用来从用于初始化它的initializer的类型中确定x的类型。
这意味着大多数编译器需要实现auto的类型推断机制已经存在并用于模板,对于任何试图实现C++98/03的编译器来说,添加对auto的支持似乎非常容易。因此,几乎所有的编译器团队都很快地添加了对它的支持,而且似乎与此相关的错误很少。
当这个答案最初写成(在C++ 11标准还没有定稿的2011年),auto已经非常可移植。如今,在所有主流编译器中,它都是完全可移植的。唯一明显避免使用它的原因是,如果你需要编写与C编译器兼容的代码,或者你有特定的需要针对一些你知道不支持它的小众编译器(例如,一些人仍然使用Borland、Watcom等公司几十年前发布的编译器编写MS-DOS代码),那么你需要避免使用它。但是,如果你使用的是任何主流编译器的合理当前版本,完全没有理由避免使用它。
标准的更近一些的修订已经添加了一些新的地方可以使用auto。从C++14开始,你可以在lambda的参数类型中使用auto
    [](auto s) { return s + 1; }

这与上面的示例基本相同-尽管它没有明确使用template语法,但这基本上是一种能够推断参数类型并在该类型上实例化模板的模板。

这非常方便和有用,在C++20中为普通函数添加了相同的功能,而不仅仅是Lambda函数。

但是,就像以前一样,所有这些都归结为自C++98以来我们一直使用的相同基本类型推断机制。 auto允许在更多地方更方便地使用它,但底层的重型工作仍然保持不变。


2
自从C++20以来,也可以使用auto作为函数参数类型 - Anderson Green

32

这只是将一个通常无用的关键词赋予一种新的、更好的功能。在C++11中是标准的,在大多数支持C++11的编译器中都可以使用。


1
哦!啊哈,从没想过C++语言本身也可以改变。我得去查一下C++11中添加了什么其他内容,我听说过C++0x,但从未深入研究过。 - Anne Quinn
9
C++0x是一个临时名称。它在本月已发布,因此成为C++11。 - R. Martinho Fernandes

26

对于变量,指定正在声明的变量类型将从其初始化器自动推断。对于函数,指定返回类型是尾随返回类型或将从其返回语句中推断(自C++14以来)。

语法

auto variable initializer   (1) (since C++11)

auto function -> return type    (2) (since C++11)

auto function   (3) (since C++14)

decltype(auto) variable initializer (4) (since C++14)

decltype(auto) function (5) (since C++14)

auto :: (6) (concepts TS)

cv(optional) auto ref(optional) parameter   (7) (since C++14)

说明

  1. 在块作用域、命名空间作用域、for循环的初始化语句等情况下,关键字auto可用作类型指定符号来声明变量。

    一旦初始化程序的类型确定后,编译器将使用函数调用模板实参推导规则(详见模板实参推导#其他上下文中的细节)确定替换关键字auto的类型。 auto关键字可以伴随修饰符,例如const或&,这些修饰符将参与类型推导。例如,给定代码const auto& i = expr;,如果编译函数调用f(expr),则i的类型正是虚构模板template<class U> void f(const U& u) 中参数u的类型。因此,auto&&可能被推导为左值引用或右值引用,具体取决于初始化程序,该初始化程序用于范围-for循环。

    如果使用auto来声明多个变量,则推断出的类型必须匹配。例如,声明auto i = 0, d = 0.0;是不合法的,而声明auto i = 0, *p = &i;是合法的且自动推断为int类型。

  2. 在使用尾置返回类型语法的函数声明中,关键字auto不执行自动类型检测。它仅作为语法的一部分。

  3. 在未使用尾置返回类型语法的函数声明中,关键字auto指示返回类型将从其return语句的操作数中推导出,具体方法是使用模板实参推导规则。

  4. 如果变量的声明类型为decltype(auto),则关键字auto将被替换为其初始值表达式(或表达式列表),并且根据decltype的规则推导出实际类型。

  5. 如果函数的返回类型声明为decltype(auto),则关键字auto将被替换为其return语句的操作数,并且根据decltype的规则推导出实际返回类型。

  6. 形式为auto::的嵌套名称指定符号是一个占位符,将按照约束类型占位符推导的规则替换为类或枚举类型。

  7. lambda表达式中的参数声明(自C++14起)。函数参数声明(概念TS)

注释

在C++11之前,auto具有存储持续时间指定符的语义。 在一个声明中混合使用auto变量和函数,例如auto f() -> int, i = 0;是不允许的。

更多信息请参见:http://en.cppreference.com/w/cpp/language/auto


嘿 @prathamesh-aware,你能给点6提供一些参考吗?我从来没见过auto:: - undefined

17

auto关键字是C++中一个重要且经常使用的关键字。在初始化变量时,auto关键字用于类型推断(也称为类型推导)。

有三种不同的规则适用于auto关键字。

第一条规则

auto x = expr; ----> 没有指针或引用,只有变量名。在这种情况下,const和引用被忽略。

int  y = 10;
int& r = y;
auto x = r; // The type of variable x is int. (Reference Ignored)

const int y = 10;
auto x = y; // The type of variable x is int. (Const Ignored)

int y = 10;
const int& r = y;
auto x = r; // The type of variable x is int. (Both const and reference Ignored)

const int a[10] = {};
auto x = a; //  x is const int *. (Array to pointer conversion)

Note : When the name defined by auto is given a value with the name of a function,
       the type inference will be done as a function pointer.

第二条规则

auto& y = expr; 或者 auto* y = expr; ----> 在 auto 关键字后使用引用或指针。

警告:在这个规则中 const 并没有被忽略!!!

int y = 10;
auto& x = y; // The type of variable x is int&.

警告:在此规则中,数组转指针的转换(数组衰减)不会发生!!!

auto& x = "hello"; // The type of variable x is  const char [6].

static int x = 10;
auto y = x; // The variable y is not static.Because the static keyword is not a type. specifier 
            // The type of variable x is int.

第三规则

auto&& z = expr; ----> 这不是一个右值引用。

警告:如果类型推导存在疑问并且使用了 && 标记,则像这样引入的名称被称为“转发引用”(也称为通用引用)。

auto&& r1 = x; // The type of variable r1 is int&.Because x is Lvalue expression. 

auto&& r2 = x+y; // The type of variable r2 is int&&.Because x+y is PRvalue expression. 

2
讲解得非常清晰易懂。谢谢您。阅读收获颇丰。 - Ayush

16

这个功能并不是一直存在的,自2010版起Visual Studio就支持它了。这是一个新的C++11特性,因此它不仅限于Visual Studio,也可以/将会被移植到其他环境中。目前大多数编译器都已经支持这个功能。


8

auto 关键字用于指定正在声明的变量的类型将从其初始化程序中自动推断出来。对于函数而言,如果它们的返回类型为 auto,则将在运行时通过返回类型表达式进行评估。

当我们必须使用迭代器时,它非常有用。例如,对于下面的代码,我们可以简单地使用 "auto" 而不是编写整个迭代器语法。

int main() 
{ 

// Initialize set 
set<int> s; 

s.insert(1); 
s.insert(4); 
s.insert(2); 
s.insert(5); 
s.insert(3); 

// iterator pointing to 
// position where 2 is 
auto pos = s.find(3); 

// prints the set elements 
cout << "The set elements after 3 are: "; 
for (auto it = pos; it != s.end(); it++) 
    cout << *it << " "; 

return 0; 
}

这是我们如何使用 "auto" 关键字


5

这不会消失……它是在C++11的实现中作为新标准C++功能。尽管它是简化对象声明以及清理某些调用范例语法(即基于范围的for循环)的绝妙工具,但不要过度使用或滥用它 :-)


1
它的魔力在于减少为每个传递到特定函数中的变量类型编写代码的必要性。考虑Python类似于其C基础的print()函数。
#include <iostream>
#include <string>
#include <array>

using namespace std;

void print(auto arg) {
     cout<<arg<<" ";
}

int main()
{
  string f = "String";//tok assigned
  int x = 998;
  double a = 4.785;
  string b = "C++ Auto !";
//In an opt-code ASCII token stream would be iterated from tok's as:
  print(a);
  print(b);
  print(x);
  print(f);
}

1
这是否仅有效地编译为“template<class T> void print(T arg)”的模板等效形式,因此需要许多实例化(并且需要在头文件中?) - Max
1
有人可以回答 @Max 的问题吗?我也很好奇它是如何实现的。 - Arundale Ramanathan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接