C++次期バージョンの言語拡張

コンセプト的な部分は置いておいて(ここが一番重要だけど)、時期C++であるC++0xのうち、言語部分の拡張をまとめてみる。

言語拡張は以下の3タイプ。

  • templateエリアス
  • concept
  • 型推論する変数型auto

templateエリアス

template<class T> using Vec = vector<T,My_alloc<T>>;

ここは2点拡張が入っている。

  • templateのパラメータ付エリアスを作れるようになった
    • いままでのtypedefではパラメータ化ができない
  • 入れ子templateで>>をtemplateで使えるようになった

concept

sort(v);

このsortの宣言は、

template<Container C> // sort container using <
    void sort(C& c);
      
template<Container C, Predicate Cmp> // sort container using Cmp
    where Can_call_with<Cmp,typename C::value_type>
    void sort(C& c, Cmp less);

と書く、ここでは新たにconceptが導入されている。

  • いままでtypenameやclassなどが入っていたところに、ContainerやPredicateといったconceptを指定して型を制約できるようになった
    • たとえばCがContainer conceptを満たさないと、その旨のコンパイルエラーがでる
  • 新たなwhere句で、conceptのCan_call_withを使ってCmpクラスとC::value_typeとの関連を制約できるようになった

conceptはtemplateで使うパラメータクラスを制約するものである。
このconceptは、これまでtemplateでライブラリを作ったときに、コンパイルエラーをわかりやすくするために入れていた、下記のようなチェック専用関数の代わりになる。

template<class TYPE> void TYPE_requires_Comparable() {
#ifdef DEBUG
  TYPE a;
  TYPE b;
  int r = a < b;
#endif
}

template <class ElemType> void sort(List<ElemType> l) {
  TYPE_requires_Comparable<ElemType>();
  ...
}

ちなみにこういう風に作っておけばg++だと以下のようなエラーになる:

xxx.cpp: In function `void TYPE_requires_Comparable() [with TYPE = Elem]':
xxx.cpp:18:   instantiated from `void sort(List<ElemType>) [with ElemType = Elem]'
xxx.cpp:25:   instantiated from here
xxx.cpp:14: error: no match for 'operator<' in 'a < b'

concept(の定義方法)については以下の論文にある

concept Mutable_fwd<typename Iter, typename T> {
  Var<Iter> p;       // a variable of type Iter.
  Var<const T> v;    // a variable of type const T.
  Iter q = p;        // an Iter must be copy-able
  bool b = (p != q); // must support ‘‘!=’’ operation,
                     // and the resulting expression
                     // must be convertible to ‘‘bool’’
  ++p;               // must support pre-increment, no
                     // requirements on the result type
  *p = v;            // must be able to dereference p,
                     // and assign a ‘‘const T’’ to the
                     // result of that dereference; no
                     // requirements on the result type
};

concept Small<typename T, int N>
  where sizeof (T) <= N
  { };

のように書くらしい。ほかにもいろいろ例がある。たとえば、関数中に明示的にassertを使ってその型がconceptを満たすかどうかチェックできたりなどできる。

型推論する変数型auto

for (auto p = v.begin(); p!=v.end(); ++p)
    cout << *p << endl; 
  • autoで宣言した変数は型推論で型解決される。

いままでだと、きちんと正確な変数の型を書かなくてはいけなかった。しかし、template利用が多くなると、一時変数導入のために使う型名が長くなってしまっていたが、それを回避できる。

感想

どれもランタイムに拡張を必須要求するということはなく、あくまでコンパイラ拡張で済ませられるものにとどまっている。これらか拡張からC++も、ease of useな思想が強くなったと感じる。