C++17ではクラステンプレートのコンストラクターの実引数からテンプレート実引数の推定が行えるようになった。
template < typename T >
struct X
{
X( T t ) { }
} ;
int main()
{
X x1(0) ; // X<int>
X x2(0.0) ; // X<double>
X x3("hello") ; // X<char const *>
}
これは関数テンプレートが実引数からテンプレート実引数の推定が行えるのと同じだ。
template < typename T >
void f( T t ) { }
int main()
{
f( 0 ) ; // f<int>
f( 0.0 ) ; // f<double>
f( "hello" ) ; // f<char const *>
}
クラステンプレートのコンストラクターからの実引数は便利だが、クラスのコンストラクターはクラステンプレートのテンプレートパラメーターに一致しない場合もある。そのような場合はそのままでは実引数推定ができない。
// コンテナー風のクラス
template <typename T >
class Container
{
std::vector<T> c ;
public :
// 初期化にイテレーターのペアを取る。
// IteratorはTではない。
// Tは推定できない
template < typename Iterator >
Container( Iterator first, Iterator last )
: c( first, last )
{ }
} ;
int main()
{
int a[] = { 1,2,3,4,5 } ;
// エラー
// Tを推定できない
Container c( std::begin(a), std::end(a) ) ;
}
このため、C++17には推定ガイドという機能が提供されている。
テンプレート名( 引数リスト ) -> テンプレートid ;
これを使うと、以下のように書ける。
template < typename Iterator >
Container( Iterator, Iterator )
-> Container< typename std::iterator_traits< Iterator >::value_type > ;
C++コンパイラーはこの推定ガイドを使って、Container<T>::Container(Iterator, Iterator)からは、Tをstd::iterator_traits< Iterator>::value_typeとして推定すればいいのだと判断できる。
例えば、初期化リストに対応するには以下のように書く。
template <typename T >
class Container
{
std::vector<T> c ;
public :
Container( std::initializer_list<T> init )
: c( init )
{ }
} ;
template < typename T >
Container( std::initializer_list<T> ) -> Container<T> ;
int main()
{
Container c = { 1,2,3,4,5 } ;
}
C++コンパイラーはこの推定ガイドから、Container<T>::Container( std::initializer_list<T> )の場合はTをTとして推定すればよいことがわかる。
機能テストマクロは__cpp_deduction_guides, 値は201606。