【问题标题】:C++ auto keyword. Why is it magic?C++ 自动关键字。为什么是魔法?
【发布时间】:2011-11-26 11:27:48
【问题描述】:

从我用来学习 C++ 的所有资料来看,auto 一直是一个奇怪的存储持续时间说明符,没有任何用途。但就在最近,我遇到了将它本身用作类型名称的代码。出于好奇,我尝试了它,它假定我碰巧分配给它的类型!

突然间,STL 迭代器以及任何使用模板的东西都变得容易编写 10 倍。感觉就像我在使用 Python 这样的“有趣”语言。

我的一生都在哪里?你会说它是 Visual Studio 独有的还是不可移植的,这会打破我的梦想?

【问题讨论】:

标签: c++ types c++11 auto


【解决方案1】:

auto 是 C++ 从 C“继承”的一个关键字,它几乎永远存在,但实际上从未使用过,因为只有两种可能的情况:要么不允许,要么默认情况下假定它。

使用auto 表示推导类型是 C++11 的新功能。

同时,auto x = initializerinitializer 的类型推导出x 的类型,与函数模板的模板类型推导工作方式相同。考虑这样的函数模板:

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

在点 A,已根据传递给 whatever 的参数值将类型分配给 T。当你做auto x = initializer;时,同样的类型推导用于从用于初始化它的initializer的类型中确定x的类型。

这意味着编译器需要实现auto 的大多数类型推导机制已经存在并用于任何编译器上的模板,甚至尝试实现 C++98/03。因此,添加对auto 的支持显然对几乎所有编译器团队来说都相当容易——它添加得非常快,而且似乎也几乎没有与它相关的错误。

最初编写此答案时(在 2011 年,在 C++ 11 标准上墨迹未干之前)auto 已经非常便携。如今,它在所有主流编译器中完全可移植。避免它的唯一明显原因是,如果您需要编写与 C 编译器兼容的代码,或者您有特定的需要针对一些您知道不支持它的利基编译器(例如,仍然有一些人编写代码对于 MS-DOS,使用 Borland、Watcom 等的编译器,几十年来没有出现重大升级)。如果您使用的是任何主流编译器的合理最新版本,那么完全没有理由避免它。

该标准的最新修订版添加了一些可以使用auto 的新位置。从 C++14 开始,您可以使用 auto 作为 lambda 的参数类型:

    [](auto s) { return s + 1; }

这与上面的示例基本相同——尽管它没有显式使用template 语法,但这基本上是一个模板,它推断参数的类型,并在该类型上实例化模板。

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

但是,就像以前一样,所有这些实际上都归结为使用自 C++98 以来我们用于函数模板的相同基本类型推导机制。 auto 允许在更多地方、更方便地使用它,但基本的繁重工作保持不变。

【讨论】:

【解决方案2】:

它只是采用一个通常无用的关键字并赋予它一个新的、更好的功能。它在 C++11 中是标准的,大多数支持 C++11 的 C++ 编译器都会支持它。

【讨论】:

  • 哦!啊哈,从来没有想过 C++ 这种语言是一种可以自行改变的东西。我将不得不查看他们在这个 C++11 中添加的其他内容,我听说过一点 C++0x,但从未深入研究过。
  • @Clairvoire C++0x 是临时名称。它已于本月发布,因此成为 C++11。
【解决方案3】:

对于变量,指定正在声明的变量的类型将自动从其初始化程序中推导出来。对于函数,指定返回类型是尾随返回类型或将从其返回语句中推导出来(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 的类型(有关详细信息,请参阅模板参数推导#Other contexts)。关键字 auto 可能伴随着修饰符,例如 const 或 &,它们将参与类型推导。例如,给定const auto&amp; i = expr;,如果函数调用f(expr) 已编译,则i 的类型正是虚构模板template&lt;class U&gt; void f(const U&amp; u) 中的参数u 的类型。因此,auto&& 可以根据初始化器推导出为左值引用或右值引用,用于基于范围的 for 循环。

    如果使用 auto 声明多个变量,则推导的类型必须匹配。例如,声明auto i = 0, d = 0.0; 是非良构的,而声明auto i = 0, *p = &amp;i; 是良构的并且auto 被推导出为int。

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

  3. 在不使用尾随返回类型语法的函数声明中,关键字 auto 表示将使用模板参数推导规则从其返回语句的操作数推导返回类型。

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

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

  6. auto:: 形式的嵌套名称说明符是一个占位符,它被遵循约束类型占位符推导规则的类或枚举类型替换。

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

注意事项

在 C++11 之前,auto 具有存储持续时间说明符的语义。 不允许在一个声明中混合自动变量和函数,如 auto f() -&gt; int, i = 0;

欲了解更多信息:http://en.cppreference.com/w/cpp/language/auto

【讨论】:

    【解决方案4】:

    这个功能在你的一生中都没有。自 2010 版本以来,它已在 Visual Studio 中得到支持。这是一个新的 C++11 功能,因此它不是 Visual Studio 独有的,并且是/将是可移植的。大多数编译器已经支持它。

    【讨论】:

      【解决方案5】:

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

      关于 auto 关键字有 3 种不同的规则。

      第一条规则

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

      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&amp; 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&amp;&amp; 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. 
      

      【讨论】:

      • 解释得很好。谢谢你。非常丰富的阅读。
      【解决方案6】:

      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”关键字

      【讨论】:

        【解决方案7】:

        它不会去任何地方......它是 C++11 实现中的一个新的标准 C++ 功能。话虽如此,虽然它是简化对象声明以及清理某些调用范式(即基于范围的 for 循环)的语法的绝佳工具,但不要过度使用/滥用它 :-)

        【讨论】:

          【解决方案8】:

          它的神奇之处在于它能够减少为传递给特定函数的每个变量类型编写代码的能力。在它的 C 基础中考虑一个类似 Python 的 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);
          }
          

          【讨论】:

          • 这是否有效地编译成模板等效于template&lt;class T&gt; void print(T arg),因此需要许多实例化(并且需要在标题中?)
          猜你喜欢
          • 2010-10-18
          • 1970-01-01
          • 1970-01-01
          • 2013-02-04
          • 2012-01-15
          • 2012-06-18
          • 1970-01-01
          • 1970-01-01
          • 2012-05-14
          相关资源
          最近更新 更多