【C/C++】autoキーワードの使用

4398 ワード

一、C++98 auto
以前からC++98規格にautoキーワードが存在していたが、その時のautoは変数を自動変数として宣言するために使用され、自動変数は自動的なライフサイクルを持つことを意味していた.これは余計なことだ.auto宣言を使用しなくても、変数は自動的なライフサイクルを持っているからだ.
int a =10 ;         //       
auto int b = 20 ;   //       
static int c = 30 ; //      

C++98のautoは余計で使用が少なく,C++11はこの用法を削除し,代わりに新しいauto:変数の自動タイプ推定である.
二、C++11 auto
autoは変数を宣言するときに変数の初期値のタイプに基づいて自動的にこの変数に一致するタイプを選択することができ、類似のキーワードにはdecltypeもあります.例を挙げます.
int a = 10;
auto au_a = a; //      ,au_a int  
cout << typeid(au_a).name() << endl;

typeid演算子は変数のタイプを出力できます.プログラムの実行結果が出力されました.
int
この使い方はC#のvarキーワードに似ています.autoの自動タイプ推定はコンパイル期間に発生するため,autoを使用してもプログラム実行時の効率が低下することはない.コンパイル期間の時間がかかるかどうかは、できないと思いますが、autoを使用していない場合、コンパイラも右操作数のタイプを知り、左操作数のタイプと比較して、対応する変換が発生するかどうか、暗黙的なタイプ変換が必要かどうかを確認する必要があります.
三、autoの使い方
上記の例は簡単ですが、実際にプログラミングするときもautoを使うことをお勧めしません.直接変数を書くタイプはもっと分かりやすいです.以下、autoキーワードの正しい使い方を列挙します.
3.1、冗長で複雑な変数の代わりに使用する、変数の使用範囲が独自の変数宣言
autoがない場合、標準ライブラリを操作するときによく必要なことを想像してみてください.
#include
#include
int main()
{
    std::vector<:string> vs;
    for (std::vector<:string>::iterator i = vs.begin(); i != vs.end(); i++)
    {
        //...
    }
}

このようにコードを書くのは本当にうんざりしている.なぜusing namespace stdを直接使用しないのか、コードを短くすることができると言う人もいるかもしれません.実際にはこの提案の方法ではない(C++Primerはこれについて述べている).autoを使用すると、コードを簡略化できます.
#include
#include
int main()
{
    std::vector<:string> vs;
    for (auto i = vs.begin(); i != vs.end(); i++)
    {
        //..
    }
}

forループのiは、長い列を明示的に定義することなく、コンパイル時にそのタイプを自動的に導出します.
3.2.テンプレート関数を定義する際、テンプレートパラメータに依存する変数のタイプを宣言する
template 
void Multiply(_Tx x, _Ty y)
{
    auto v = x*y;
    std::cout << v;
}

auto変数を使用してvを宣言しないと、この関数は定義しにくくなります.コンパイルしないうちに、x*yの本当のタイプは何なのか誰が知っていますか.
3.3、テンプレート関数はテンプレートパラメータの戻り値に依存する
template 
auto multiply(_Tx x, _Ty y)->decltype(x*y)
{
    return x*y;
}

テンプレート関数の戻り値がテンプレートのパラメータに依存する場合、コードをコンパイルする前にテンプレートパラメータのタイプを決定することはできません.したがって、戻り値のタイプも分かりません.この場合、autoを使用して、上記のようにフォーマットできます.
decltypeオペレータは、クエリー式のデータ型に使用され、C++11規格で導入された新しい演算子でもあり、汎用プログラミングでテンプレートパラメータによって決定されるタイプがあり、その問題を表すことが難しいことを解決することを目的としています.
autoのここでの役割は戻り値占有とも呼ばれ、関数戻り値が1つの位置を占めているだけで、本当の戻り値は後ろのdecltype(_Tx*_Ty)である.なぜ戻り値を後置するのですか?バックグラウンドがない場合、関数は次のように宣言されます.
decltype(x*y)multiply(_Tx x, _Ty y)

このときx,yはまだ宣言されておらず,コンパイルは通過できない.
四、注意事項
  • auto変数は、constキーワードと同様に定義時に初期化する必要があります.
  • は、1つのautoシーケンスに定義される変数を常に同じタイプに導く必要がある.例:
  • auto a4 = 10, a5 = 20, a6 = 30;    //  
    auto b4 = 10, b5 = 20.0, b6 = 'a'; //  ,         

    4.1、autoキーワードを使用してタイプ自動導出を行う場合、以下の規則を順次適用する.
  • 初期化式が参照である場合、参照の意味
  • が除去される.
    int a = 10;
    int &b = a;
    
    auto c = b;  //c    int  int&(    )
    auto &d = b; //  c     int&
    
    c = 100;     //a =10;
    d = 100;     //a =100;
  • 初期化式がconstまたはvolatile(または両方)である場合、const/volatileの意味
  • が除去される.
    const int a1 = 10;
    auto  b1= a1;       //b1    int  const int(  const)
    const auto c1 = a1; //  c1    const int
    b1 = 100;           //  
    c1 = 100;           //  
  • autoキーワードに&番号が付いている場合、const語意
  • は除去されません.
    const int a2 = 10;
    auto &b2 = a2; //  auto  &,    const,b2   const int
    b2 = 10;       //  

    これはconstをどのように削除したのか,b 2がa 2の非const参照であり,b 2によってa 2の値を変えることができるのは明らかに不合理であるからである.
  • 初期化式が配列である場合、autoキーワード導出タイプはポインタ
  • である.
    int a3[3] = { 1, 2, 3 };
    auto b3 = a3;
    cout << typeid(b3).name() << endl;

    プログラムしゅつりょく
    int *
  • 式が配列でautoバンド上&の場合、導出タイプは配列タイプ
  • である.
    int a7[3] = { 1, 2, 3 };
    auto & b7 = a7;
    cout << typeid(b7).name() << endl;

    プログラムしゅつりょく
    int [3]
  • 関数またはテンプレートパラメータはauto
  • と宣言できません.
    void func(auto a)  //  
    {
        //... 
    }
  • autoは本当のタイプではないことに注意してください.
  • autoは単なるプレースホルダであり、本格的なタイプではなく、sizeofやtypeidなどのタイプをオペランドとするオペレータを使用することはできません.
    cout << sizeof(auto) << endl;//  
    cout << typeid(auto).name() << endl;//