C++自動タイプ推定

7202 ワード

C++言語は、コード書き込みを簡略化するための自動タイプ推定メカニズムを提供しています.これは、autodecltypeを使用して、自動タイプ推定の作業を完了することができ、コンパイル期間中に動作します.これは、実行時にパフォーマンスの損失がないことを示しています.
一、auto自動タイプ推定auto自動タイプ推定のメカニズムは関数テンプレートの推定メカニズムとよく似ており、autoはテンプレート内のTに似ている.
(1.1)auto変数を値伝達で初期化する
一言でまとめると、オブジェクトのconstと参照属性を捨てて、新しいオブジェクトは新しいコピーのようです.ポインタの場合、最上位constプロパティは破棄され、最下位constプロパティは保持されます.
int main(int argc, char *argv[])
{
    int a = 0;
    int &a_ref = a;
    const int ca = 0;
    const int &ca_ref = ca;
    const int *const pa = &a;
    int arr[] = {1, 2, 3};
    const carr[] = {1, 2, 3};
    
    //  、    。
    auto b1 = a; // b1 int, auto int
    auto b2 = a_ref; // b2 int, auto int
    auto b3 = ca; // b3 int, auto int
    auto b4 = ca_ref; // b4 int, auto int
    auto b5 = pa; // b5 const int *, auto const int *
    auto b6 = arr; // b6 int*, auto int*
    auto b7 = carr; // b7 const int*, auto const int*
    auto b8 = main; // b8 int(*)(int, char**), auto int(*)(int,char**)
    return 0;
}

(1.2)auto変数のポインタまたは参照タイプの初期化
一言でまとめると、参照属性は捨てられますが、const属性は保持されます.ポインタタイプの場合、すべてのconstプロパティが保持されます.
int main(int argc, char *argv[])
{
    int a = 0;
    int &a_ref = a;
    const int ca = 0;
    const int &ca_ref = ca;
    const int *const pa = &a;
    int arr[] = {1, 2, 3};
    const int carr[] = {1, 2, 3};

    //  、        。
    auto &b1 = a; // b1 int&, auto int
    auto &b2 = a_ref; // b2 int&, auto int
    auto &b3 = ca; // b3 const int&, auto const int
    auto &b4 = ca_ref; // b4 const int&, auto const int
    auto &b5 = pa; // b5 const int *const &, auto const int *const
    auto &b6 = arr; // b6 int*&, auto int*
    auto &b7 = carr; // b7 const int *&, auto const int *
    auto &b8 = main; // b8 int(&)(int, char**), auto int(int,char**)
    return 0;
}

(1.3)auto変数の万能参照初期化
万能参照を参照してください:C++参照の詳細.
二、decltype自動タイプ推定decltypeは、autoのように定数および参照を破棄する可能性がないため、autoよりも穏やかである.式の値で変数を初期化したくなく、式のデータ型を推定したい場合にのみdecltypeを使用します.
(2.1)decltype推定変数のタイプdecltype推定の方法は非常に簡単です.元のタイプは何ですか.推定の結果は何ですか.
int main(int argc, char *argv[])
{
    int a = 0;
    int &ra = a;
    const int &cra = a;
    int *pa = &a;
    const int *cpa = pa;
    const int *const ccpa = pa;

    decltype(a) b1 = a; // b1 int
    decltype(ra) b2 = a; // b2 int&
    decltype(cra) b3 = a;// b3 const int&
    decltype(pa) b4 = nullptr; // b4 int*
    decltype(cpa) b5 = nullptr; // b5 const int *
    decltype(ccpa) b6 = nullptr; // b6 const int *const 
    return 0;
}

(2.2)decltype推定式のタイプ
推定変数とは異なり、decltype式の内容が左の場合、参照タイプとして推定されます.
int main(int argc, char *argv[])
{
    int a = 0;
    int *pa = &a;

    decltype(1 + 2) b1; //    int。 
    decltype(*pa) b2 = a; //   *pa   ,  b    int&。
    decltype((a)) b3 = a; //   (a)    ,    ,  b    int&。
    return 0;
}

(2.3)decltype推定関数または関数の呼び出し結果
個人的にはdecltypeが最も強力な場所だと思います.この場合、実際に関数を呼び出すのではなく、タイプを推定するだけです(sizeofと非常に似ています):
#include 

std::string func() { return std::string(); }

int main(int argc, char *argv[])
{
    decltype(func) a; // a     :std::string();
    decltype(func) *b = nullptr; // b     :std::string(*)();
    decltype(func) &c = func; // c     :std::string(&)();
    decltype(func().c_str()) d = nullptr; // d const char *
                                          //       func() c_str()。
    return 0;
}

(2.4)decltypeの特殊用法例
(2.4.1)decltypeによる変数宣言のコード互換性の向上decltypeを使用すると、テンプレートプログラミングでデータ型のダイナミック効果を実現できます.
template
class container_copier
{
public:
    typename T::iterator _begin;
    typename T::iterator _end;
    
    container_copier(typename T::iterator begin, typename T::iterator end) 
        : _begin(begin), _end(end) {}
    
    void copy() { /* ... */ }
};

このテンプレートは通常のコンテナタイプに対応しますが、定数コンテナオブジェクトに対しては操作できません.
#include 

int main(int argc, char *argv[])
{
    std::vector vec = {1, 2, 3, 4, 5};
    container_copier<:vector>> cpr1(vec.begin(), vec.end());
    cpr1.copy(); // OK.
    
    const std::vector cvec = {1, 2, 3, 4, 5};
    container_copier> cpr2(vec.begin(), vec.end()); //    
    
    return 0;
}

エラーの原因は、定数コンテナの場合、begin関数がconst_を返します.iteratorではなくiteratorです.オートタイプ推定が適用されなければ、偏特化せざるを得ません.
template 
class container_copier
{
public:
    typename T::const_iterator _begin;
    typename T::const_iterator _end;
    
    container_copier(typename T::const_iterator begin, typename T::const_iterator end) 
        : _begin(begin), _end(end) {}
    
    void copy() { /* ... */ }
};

このようにしてこそ、コンパイルを通過することができます.このように偏特化コードを繰り返し書くのは間違いなく面倒だ.しかし、自動タイプ推定を使用すると、簡単になります.
#include 

template
class container_copier
{
public:
    decltype(T().begin()) _begin;
    decltype(T().end()) _end;

    container_copier(decltype(T().begin()) begin,
                     decltype(T().end()) end)
        : _begin(begin), _end(end) {}

    void copy() { /* ... */ }
};

int main(int argc, char *argv[])
{
    std::vector vec = {1, 2, 3, 4, 5};
    container_copier<:vector>> cpr1(vec.begin(), vec.end());
    cpr1.copy(); // OK.
    
    const std::vector cvec = {1, 2, 3, 4, 5};
    container_copier> cpr2(vec.begin(), vec.end()); // OK.
    
    return 0;
}

このように、自動タイプ推定により、iteratorを使用するか、const_iteratorを使用するかをコンパイラによって動的に決定することができる.
(2.4.2)decltypeを用いて関数戻りタイプの互換性を向上させる
場合によっては、関数がパラメータ化されたメソッドの戻りタイプに基づいて関数の戻りタイプを決定したい場合があります.これにより、自動タイプ推定を使用できます.
template
auto func(T&& t) -> decltype(t.foo())
{
    // ...
    return t.foo();
}

これにより、表示せずに戻りタイプを指定し、foo()メソッドのタイプに応じて戻りタイプを変化させることができる.
三、decltype(auto)タイプ推定(c++14)decltype(auto)の意味は、コンパイラが自動的に推定するために自動的に推定する必要があるタイプである.decltype(auto)を使用する主な目的は、autoが参照または定数属性を破棄するため、これらの属性を保持するために自動タイプ推定が必要になる場合があるため、decltypeautoが破棄した属性を取り戻すことができる.
int main(int argc, char *argv[])
{
    int a = 0;
    const int &a_ref = a;
    auto b1 = a_ref; // b1 int
    //        b1    ?
    //    :
    decltype(auto) b2 = a_ref; //    :decltype(a_ref) b2 = a_ref;
                               // b2 const int &
    //    :
    auto &b3 = a_ref;
    return 0;
}

一般的なピットは、decltypeが左値式を推定すると、参照タイプが生成されます.ただし、ローカル変数の参照を返すと危険です.
decltype(auto) func()
{
    int i = 30;
    // ...
    return(i); //   ,      :decltype((i)),     i   ,    。
    // return i;   。
}