本の虫

著者:江添亮
ブログ: http://cpplover.blogspot.jp/
メール: boostcpp@gmail.com
Twitter: https://twitter.com/EzoeRyou
GitHub: https://github.com/EzoeRyou

アマゾンの江添のほしい物リストを著者に送るとブログ記事のネタになる

筆者にブログのネタになる品物を直接送りたい場合、住所をメールで質問してください。

C++17のクラスのテンプレート実引数推定

テンプレートは以下のように定義する。

template < typename T >
class C
{
    C ( T t ) { }
} ;

template < typename T >
void f( T t ) { }

テンプレートは以下のように使う。

int main()
{
    C<int> c(42) ;
    f<int>(42) ;
}

しかし、C++プログラマーの大半は、関数テンプレートfをこのように使うことはない。大抵は、f(42)のように使う。このように、テンプレート名を書いた場合、C++コンパイラーはテンプレートの実引数推定と呼ばれる仕組みを使ってテンプレート実引数を推定する。

その詳しい仕組みは難解だが、考え方としてはこうだ。42の型はintである。すると、tの型はintである。tの型はTとされているので、Tはintである。Tはテンプレート仮引数である。するとテンプレート仮引数Tに対する実引数はintである。

テンプレートの実引数推定は、残念ながらC++14ではクラステンプレートには存在しない。しかし、上の例をみるように、クラステンプレートにもコンストラクターがあるのだから、適用できるはずだ。

C++17ではまさにクラステンプレートに実引数推定ができるようになった。以下のように書ける。

C c1(42) ;
C c2 = 42 ;

C++17では、実引数とクラステンプレートCのコンストラクターの仮引数から、クラステンプレートのテンプレート実引数を推定できるようになる。

しかし、C c(42)という形はもっとも簡単なものだ。現実には、以下のような場合もある。

template < typename T >
class C
{
    template < typename Iterator >
    C ( Iterator begin, Iterator end ) ;
} ;

int main()
{
    int a[] = { 1,2,3,4,5 } ;
    // エラー、IteratorからTは推定できない
    C c( std::begin(a), std::end(a) ) ;
}

この場合、IteratorからTは推定できないのでエラーとなる。

この問題を解決するために、C++17では、推定ガイド(deduction guide)という文法が追加される。以下のように書けば、IteratorからTが推定できる。


template < typename T >
class C
{
    template < typename Iterator >
    C ( Iterator begin, Iterator end ) ;
} ;

template < typename Iterator >
C( Iterator begin, Iterator end )
-> C< std::iterator_traits<Iterator>::value_type >

int main()
{
    int a[] = { 1,2,3,4,5 } ;
    C c( std::begin(a), std::end(a) ) ;
}

文法は以下の通り。

テンプレート名 (引数リスト) -> 実引数付きのテンプレート名