サーチ…
備考
2014年11月、C ++標準化委員会は、直接初期化構文を使用して自動およびブレースされたイニシャライザの特殊タイプの控除ルールを削除する提案N3922を採用しました。これはC ++標準の一部ではありませんが、一部のコンパイラで実装されています。
コンストラクタのテンプレートパラメータ控除
C ++ 17より前では、テンプレート控除でコンストラクタ内のクラスタイプを推論することはできません。明示的に指定する必要があります。しかし、これらの型は非常に扱いにくく、ラムダの場合は名前を付けることができないので、 make_pair()
、 make_tuple()
、 back_inserter()
などの型ファクトリがmake_pair()
ます。
これはもはや必要ではありません:
std::pair p(2, 4.5); // std::pair<int, double>
std::tuple t(4, 3, 2.5); // std::tuple<int, int, double>
std::copy_n(vi1.begin(), 3,
std::back_insert_iterator(vi2)); // constructs a back_insert_iterator<std::vector<int>>
std::lock_guard lk(mtx); // std::lock_guard<decltype(mtx)>
コンストラクターはクラステンプレートのパラメータを推測すると見なされますが、これは不十分であり、明示的な推論ガイドを提供することができます。
template <class Iter>
vector(Iter, Iter) -> vector<typename iterator_traits<Iter>::value_type>
int array[] = {1, 2, 3};
std::vector v(std::begin(array), std::end(array)); // deduces std::vector<int>
テンプレートタイプの控除
テンプレートの一般的な構文
template<typename T>
void f(ParamType param);
f(expr);
ケース1: ParamType
は参照またはポインタですが、ユニバーサルまたはフォワード参照はありません。この場合、タイプ控除はこのように動作します。コンパイラは、参照部分がexpr
に存在する場合、それを無視します。コンパイラはexpr
の型をParamType
とパターンマッチさせてT
を判定します。
template<typename T>
void f(T& param); //param is a reference
int x = 27; // x is an int
const int cx = x; // cx is a const int
const int& rx = x; // rx is a reference to x as a const int
f(x); // T is int, param's type is int&
f(cx); // T is const int, param's type is const int&
f(rx); // T is const int, param's type is const int&
ケース2: ParamType
は汎用参照または前方参照です。この場合、 expr
がrvalueの場合、型減算はcase 1と同じです。 expr
が左辺値の場合、 T
とParamType
両方が左辺値参照として推定されます。
template<typename T>
void f(T&& param); // param is a universal reference
int x = 27; // x is an int
const int cx = x; // cx is a const int
const int& rx = x; // rx is a reference to x as a const int
f(x); // x is lvalue, so T is int&, param's type is also int&
f(cx); // cx is lvalue, so T is const int&, param's type is also const int&
f(rx); // rx is lvalue, so T is const int&, param's type is also const int&
f(27); // 27 is rvalue, so T is int, param's type is therefore int&&
ケース3: ParamType
はポインタでも参照でもありません。 expr
が参照の場合、参照部分は無視されます。 expr
がconstの場合も無視されます。それが揮発性である場合は、Tの型を推測する際にも無視されます。
template<typename T>
void f(T param); // param is now passed by value
int x = 27; // x is an int
const int cx = x; // cx is a const int
const int& rx = x; // rx is a reference to x as a const int
f(x); // T's and param's types are both int
f(cx); // T's and param's types are again both int
f(rx); // T's and param's types are still both int
オートタイプの控除
auto
キーワードを使用するタイプの控除は、テンプレートタイプの控除とほぼ同じです。以下にいくつかの例を示します。
auto x = 27; // (x is neither a pointer nor a reference), x's type is int
const auto cx = x; // (cx is neither a pointer nor a reference), cs's type is const int
const auto& rx = x; // (rx is a non-universal reference), rx's type is a reference to a const int
auto&& uref1 = x; // x is int and lvalue, so uref1's type is int&
auto&& uref2 = cx; // cx is const int and lvalue, so uref2's type is const int &
auto&& uref3 = 27; // 27 is an int and rvalue, so uref3's type is int&&
相違点は以下のとおりです。
auto x1 = 27; // type is int, value is 27
auto x2(27); // type is int, value is 27
auto x3 = { 27 }; // type is std::initializer_list<int>, value is { 27 }
auto x4{ 27 }; // type is std::initializer_list<int>, value is { 27 }
// in some compilers type may be deduced as an int with a
// value of 27. See remarks for more information.
auto x5 = { 1, 2.0 } // error! can't deduce T for std::initializer_list<t>
括弧で囲まれたイニシャライザを使用するとわかるように、autoは強制的にstd::initializer_list<T>
型の変数を作成します。 T
推論できない場合、コードは拒否されます。
関数の戻り値の型としてauto
が使用されている場合は、その関数に後続の戻り値の型があることを指定します。
auto f() -> int {
return 42;
}
C ++ 14では、C ++ 11で自動許可の使用に加えて、以下のことが可能です。
末尾の戻り値の型を持たない関数の戻り値の型として使用する場合、関数の戻り値の型を、関数の本体の戻り値があればそれから導出することを指定します。
// f returns int: auto f() { return 42; } // g returns void: auto g() { std::cout << "hello, world!\n"; }
ラムダのパラメータ型で使用する場合、ラムダをジェネリックラムダと定義します。
auto triple = [](auto x) { return 3*x; }; const auto x = triple(42); // x is a const int with value 126
特別な形式decltype(auto)
は、 auto
ものではなくdecltype
型減算ルールを使用して型を推論します。
int* p = new int(42);
auto x = *p; // x has type int
decltype(auto) y = *p; // y is a reference to *p
C ++ 03以前では、 auto
キーワードはCから継承された記憶域クラス指定子とは全く異なる意味を持ちました。