web-dev-qa-db-ja.com

initializer_listとテンプレートタイプの推定

関数について考えてみましょう。

_template<typename T>
void printme(T&& t) {
  for (auto i : t)
    std::cout << i;
}
_

または、begin()/ end()が有効なタイプの1つのパラメーターを期待するその他の関数。

なぜ次は違法なのですか?

printme({'a', 'b', 'c'});

これらすべてが正当な場合:

_printme(std::vector<char>({'a', 'b', 'c'}));
printme(std::string("abc"));
printme(std::array<char, 3> {'a', 'b', 'c'});
_

これを書くことさえできます:

_const auto il = {'a', 'b', 'c'};
printme(il);
_

または

_printme<std::initializer_list<char>>({'a', 'b', 'c'});
_
35
4ZM

テンプレート引数Tを推測できなかったため、最初の行printme({'a', 'b', 'c'})は不正です。テンプレート引数を明示的に指定すると、機能します。 printme<vector<char>>({'a', 'b', 'c'})またはprintme<initializer_list<char>>({'a', 'b', 'c'})

引数の型が明確に定義されているため、リストした他の引数は正当です。したがって、テンプレート引数Tは問題なく推測できます。

autoはタイプ_std::initializer_list<char>_であると見なされるため、ilを含むスニペットも機能します。したがって、printme()へのテンプレート引数を推測できます。


ここでの唯一の「面白い」部分は、autoがタイプ_std::initializer_list<char>_を選択するが、テンプレート引数は選択しないことです。これは、C++ 11標準の§14.8.2.5/ 5が、これがテンプレート引数の非推定コンテキストであると明示的に述べているためです。

関連する引数が初期化子リスト(8.5.4)であるが、パラメーターにstd :: initializer_listがないか、cv修飾されたstd :: initializer_listタイプへの参照がない関数パラメーター。 [例:

_template<class T> void g(T);
g({1,2,3}); // error: no argument deduced for T
_

—終了例]

ただし、autoでは、§7.1.6.4/ 6は_std::initializer_list<>_を明示的にサポートしています。

初期化子がbraced-init-list(8.5.4)の場合、_std::initializer_list<U>_。

42
Lily Ballard

関数をオーバーロードして、initializer_list型の引数を明示的に取得することもできます。

template<typename T>
void printme(std::initializer_list<T> t) {
  for (auto i : t)
    std::cout << i;
}
10
John Schug

これは特に§14.8.2.5/ 5でカバーされています

関連する引数が初期化子リストであるが、パラメーターにstd::initializer_listがないか、cv修飾された可能性のあるstd::initializer_listタイプへの参照がない関数パラメーター。 [例:

template<class T> void g(T);
g({1,2,3}); // error: no argument deduced for T

—例を終了]

これを機能させるために、テンプレート引数タイプを明示的に指定できます。

printme<std::initializer_list<int>>( {1,2,3,4} );
5
Praetorian