第327章 イテレーターの型推論

クラステンプレートの型推論は一見かなり汎用的に見えますね。

かなり使いずらそうな型の推論、例えばイテレーターも推論はできます。

まずはソースコードから見てみましょう。

  1 #if __cplusplus < 201703L
  2 # pragma message "-std=c++17を指定してください"
  3 #endif
  4
  5 #include <vector>
  6 #include <iterator>
  7 #include <iostream>
  8
  9 template<class T>
 10 struct container
 11 {
 12   container( T ){}
 13
 14   template<class Iter>
 15   container(Iter b, Iter e){
 16     std::cout << *b << " " << *std::prev(e) << '\n';
 17   }
 18 };
 19
 20 #if __cplusplus >= 201703L
 21 template<class Iter>
 22 container(Iter b, Iter e)
 23   -> container<typename std::iterator_traits<Iter>::value_type>;
 24 #endif
 25
 26 int main() {
 27
 28   std::vector<int> v {2,4};
 29 #if __cplusplus >= 201703L
 30
 31 # if defined(__clang__) && (__clang_major__ < 6)
 32   container c(100);
 33   container(v.cbegin(),v.cend());
 34 #else
 35   container<int> c(100);
 36   container<int>(v.cbegin(),v.cend());
 37 #endif
 38
 39 #else
 40   container<int> c(100);
 41   container<int>(v.cbegin(),v.cend());
 42 #endif
 43
 44   return 0;
 45 }

ビルドと実行結果. 

$ g++ main.cpp -std=c++17
$ ./a.out
2 4

このコードの目的は構文のチェックです。

まずはカスタムコンテナはイテレーターを指定できるようにします。

  9 template<class T>
 10 struct container
 11 {
 12   container( T ){}
 13
 14   template<class Iter>
 15   container(Iter b, Iter e){
 16     std::cout << *b << " " <<*std::prev(e) << '\n';
 17   }
 18 };

このクラスは C++17 の推論ガイド( deduction guide )が無い場合にはテンプレート引数を指定しないと使えません。

てなことで推論ガイドをつけてみます。

 20 #if __cplusplus >= 201703L
 21 template<class Iter>
 22 container(Iter b, Iter e)
 23   -> container<typename std::iterator_traits<Iter>::value_type>;
 24 #endif

これは std::iterator_traits テンプレートを使って Iter ポインターが指すベース型を取得して container のテンプレート引数として設定しています。

Copyright 2017-2018, by Masaki Komatsu