【Effective modern C++精製】『タイプ導出』-Item 2:『autoのタイプ導出』

7121 ワード

  • aoto関数テンプレートのパラメータタイプ導出に類似する導出規則
  • aotoと関数テンプレートのパラメータタイプ導出の違い
  • autoが関数の戻りに使用され、lambdaパラメータが使用される場合
  • Things to Remember




  • aotoと関数テンプレートのパラメータタイプは類似の導出規則を導く
    関数テンプレートタイプ導出と比較
    template<typename T>
    void f(ParamType);
    
    f(expr);
    autoによって変数が宣言されると、autoはテンプレート内のTと同じ役割を果たし、変数のタイプ説明子はテンプレートのParamTypeの役割を果たす.
    auto x = 27;        //         auto  
    const auto cx = x;  //         const auto
    const auto& rx = x; //         const auto&

    関数テンプレートのタイプ導出と同様にautoタイプ導出も3つのcaseに分けられる.
    Case1. タイプ説明子は、汎用参照ではなくポインタ/参照です.
    int x = 27;
    const auto& rx = x; // const int&

    Case2. タイプ説明子が共通参照の場合
    int x = 27;
    const int cx = 27;
    
    auto&& uref1 = x;   // x      , uref1's type => int&
    auto&& uref2 = cx;  // cx   const   , uref2's type => const int&
    auto&& uref3 = 27;  // 27      , uref3's type => int&&

    Case3. タイプ説明子はポインタでも参照でもない
    auto x = 27;        // x'type => int
    const auto cx = x;  // x'type => const int

    関数と配列の場合
     const char name[] = "abc";
    
     auto arr1 = name;  // arr1'type => const char*
     auto& arr2 = name; // arr2'type => const char(&)[4]
    
    -------------
    void someFunc(int,double);
    
    auto func1 = someFunc;  // func1'type => void(*)(int,double)
    auto& func2 = someFunc; // func2'type => void(&)(int,double)

    aotoと関数テンプレートのパラメータタイプの導出の違い
    C++11は、以下のように初期化の価値のある方法を追加しました.
    int x1 = 27;
    int x2(27);
    
    int x3 = {27};
    int x4{27};

    4つの構文ですが、結果は同じです.つまり、intタイプ変数を作成します.同様に、この構文はautoに適用されます.
    auto x1 = 27;
    auto x2(27);
    
    auto x3 = {27};
    auto x4{27};

    しかし、この2つの初期化構文の意味は異なり、{args...}で定義された変数を使用し、そのタイプは実際にはstd::initializer_listであり、値27の要素を含む.
    関数テンプレートタイプによって導出される規則では、autoのように{args...}という初期化リストの形式を自動的に適合させることはサポートされていない.
    template<typename T>
    void f(T param);
    
    f({1,2,3}); //     !!!   T    !!!
    
    auto x{1,2,3}; // OK!!!

    関数テンプレートタイプの導出は、次のようにのみ行います.
    templateT>
    void f(std::initializer_list initList);
    
    f({1,2,3}); //    !!!

    したがって、autoと関数テンプレートのタイプが導いた本当の違いは、autoが天然にstd::initializer_listをサポートする{args...}の初期化方式であり、関数テンプレートはだめである.
    関数の戻りにautoが使用され、lambdaパラメータが使用される場合
    C++14 autoは、関数宣言の戻りタイプに使用される場合、戻り値が導出可能であることを示す.しかし、自然導出std::initializer_list、すなわち{args...}の形で戻ることはサポートされていない.ここで、autoは「autoタイプ導出ではなく、テンプレートタイプ導出をサポートする」ことを提供する.
    auto createInitList()
    {
        int a = 27;
        return a;       //   int  
    }
    
    auto createInitList()
    {
        return {1,2,3};       //   !!!
    }

    autoはlambda式のパラメータにも使用できます.同様に、autoタイプの導出ではなく、パラメータが「関数テンプレートタイプ導出」をサポートすることを示します.したがって、initializer_list{args...}の自然導出もサポートされていない.
    std::vector v;
    ...
    auto resetV =
     [&v](const auto& newValue){ v = newValue;};
    ...
    resetV({1,2,3});    //   !!!

    Things to Remember
  • autoタイプ導出はテンプレートタイプ導出と同じですが、autoはstd::initializer_を自然にサポートできます.Listタイプは導出されますが、テンプレートはできません.
  • 関数は、タイプまたはlambdaパラメータのautoを返し、autoタイプ導出ではなくテンプレートタイプ導出を表す.