(Translated by https://www.hiragana.jp/)
コンセプト (C++) - Wikipedia

コンセプトえい: concept)は、プログラミング言語げんご機能きのう。かつてC++への採用さいよう検討けんとうされていたが、見送みおくられた。ISO/IEC JTC1/SC22/WG21 C++ 標準ひょうじゅん委員いいんかいによるC++0x策定さくていにおいて2009ねん前半ぜんはんまで検討けんとうされ、規格きかくしょのドラフトにもまれていたが、2009ねん7がつ13にち投票とうひょう削除さくじょされることがまった[1]

背景はいけい

編集へんしゅう

C++では、テンプレートクラス・関数かんすう引数ひきすうとするかた必然ひつぜんてきなんらかの制限せいげんす。たとえば、STLコンテナは格納かくのうするかたにデフォルトコンストラクタを要求ようきゅうする。Foo&かたのオブジェクトをける関数かんすうにはFooのあらゆるサブタイプをわたせる、というようなクラス階層かいそうによって提供ていきょうされる動的どうてきたいとはちがい、テンプレート引数ひきすうには、テンプレートが使つか演算えんざんをサポートするクラスならばなんでもわたすことが出来できる。しかし、通常つうじょう関数かんすう場合ばあい引数ひきすうたいする要求ようきゅう明確めいかくである(さきれいなら、Fooのサブタイプであること)が、テンプレートの場合ばあいは、オブジェクトがたなければならないインターフェースはテンプレート定義ていぎなかかくれてしまっている。コンセプトはテンプレート引数ひきすうたなくてはならないインターフェースを明文化めいぶんかする機構きこう提供ていきょうする。

コンセプトを導入どうにゅうする理由りゆうひとつは、エラーメッセージしつ改善かいぜんである。テンプレートが必要ひつようとするインターフェースをっていないかたをプログラマが使つかおうとした場合ばあい、コンパイラはエラーをす。しかし、そのたねのエラーは理解りかいしがたいものになりやすく、とく初心者しょしんしゃには非常ひじょう難解なんかいである。この理由りゆうとしては、エラーメッセージにテンプレート引数ひきすう省略しょうりゃくされずに表示ひょうじされ、非常ひじょうながいエラーメッセージが出力しゅつりょくされてしまうことがおおいことがげられる。コンパイラによっては、単純たんじゅんなミスがすうキロバイトものエラーメッセージを結果けっかになることもある。理由りゆうとして、エラーメッセージがエラーの実際じっさい理由りゆう明確めいかくしめしていないことがある、ということもある。たとえば、コピーコンストラクタをたないオブジェクトのvector構築こうちくしようとした場合ばあい大抵たいてい場合ばあいのエラーメッセージは「内包ないほうするオブジェクトにコピーコンストラクタをんでしまったvectorクラス」に言及げんきゅうするものになってしまう。熟練じゅくれんしたプログラマでないと、本当ほんとうのエラーが「vectorわたしたかたvector要件ようけんたしきれていないこと」がわからないだろう。

機能きのう概要がいよう

編集へんしゅう

コンセプトが記載きさいされた最後さいご規格きかくしょドラフトである N2914[2]記述きじゅつもとづいて説明せつめいする。

コンセプトは、名前なまえきの構造こうぞうであり、かた提供ていきょうしなければならない機能きのう指定していする。このてんは、オブジェクト指向しこうプログラミングで、かたおこなえることの制限せいげん定義ていぎ基底きていクラスによりおこなうのにている。しかしオブジェクト指向しこうプログラミングとはちがい、コンセプトの定義ていぎ自体じたいにはテンプレートにわたされるかた明示めいじてき関連付かんれんづけられず、テンプレート定義ていぎがわむすびつけられる:

template<LessThanComparable T>
const T& min(const T &x, const T &y)
{
  return x < y ? x : y;
}

テンプレートがた引数ひきすうclasstypename使つか任意にんいかた指定していするのではなく、前方ぜんぽう定義ていぎされたコンセプトであるLessThanComparable使用しようしている。テンプレート関数かんすうminわたされたかたがコンセプトLessThanComparableたさない場合ばあい、コンパイルエラーとなり、テンプレート実体じったい使つかわれたかたLessThanComparableコンセプトに適合てきごうしなかったことが報告ほうこくされる。

より一般いっぱんてきなコンセプトの使用しよう記法きほうは、以下いかのようになる:

template<typename T> requires LessThanComparable<T>
const T& min(const T &x, const T &y)
{
  return x < y ? x : y;
}

requiresキーワードののちには、コンセプト宣言せんげんのリストがつづく。これにより、複数ふくすうかた使つかうコンセプトを使用しようできる。また、requires !LessThanComparable<T>のようにもちいることも出来でき、あるコンセプトに合致がっちするかた使用しよう禁止きんしすることが出来できる。これらの機能きのうは、テンプレートの特殊とくしゅ同様どうよう方法ほうほう使用しようできる。一般いっぱんてきなテンプレートをすくない機能きのうしか使つかわないものとして定義ていぎし、さらに機能きのうなコンセプトをもちいた特殊とくしゅ用意よういすることで、その機能きのうもちいてたかいパフォーマンスや高機能こうきのうせい実現じつげんできる。

コンセプトは以下いかのように定義ていぎされる:

auto concept LessThanComparable<typename T>
{
  bool operator<(T, T);
}

このれいふくまれているキーワードautoは、コンセプトに記述きじゅつされた操作そうさ提供ていきょうするあらゆるかたがコンセプトをたすこととする、ということをしめすものである。autoキーワードが場合ばあい、コンセプトをたすかた宣言せんげんするのにコンセプトマップを使つか必要ひつようがある。

このコンセプトは、「自身じしんおながた引数ひきすうふたり、boolをかえ演算えんざん < つあらゆるかたLessThanComparableである」ということをしめしている。演算えんざん大域たいいき関数かんすうではなく、かたTのメンバ関数かんすうでなくてはならない。

コンセプトは、複数ふくすうかたふくむことも出来できる。たとえば、ふたつのかたをとり、片方かたがたがもう片方かたがたかたへと変換へんかんできる、ということをあらわすコンセプトは:

auto concept Convertible<typename T, typename U>
{
  operator U(const T&);
}

これをテンプレートで使つかうためには、コンセプトの一般いっぱんてき使用しよう記法きほう使つか必要ひつようがある:

template<typename U, typename T> requires Convertible<T, U>
U convert(const T& t)
{
  return t;
}

コンセプトはふくごうできる。たとえば、Regularというコンセプトがあたえられている場合ばあい:

concept InputIterator<typename Iter, typename Value>
{
  require Regular<Iter>;
  Value operator*(const Iter&);
  Iter& operator++(Iter&);
  Iter operator++(Iter&, int);
}

InputIteratorコンセプトにわたされたテンプレート引数ひきすうひとは、Regularコンセプトをたすことが確認かくにんされる。

継承けいしょうおこなうように、コンセプトものコンセプトから派生はせいできる。そして、クラスの継承けいしょうのように、派生はせいコンセプトも基底きていコンセプトの要件ようけんたす。派生はせいコンセプトは、クラスの派生はせいのように定義ていぎされる:

concept ForwardIterator<typename Iter, typename Value> : InputIterator<Iter, Value>
{
  //ここに要件ようけん追記ついきする。
}

コンセプトに型名かためい (typename)をむすけることもできる。これにより、型名かためい使用しよう可能かのうであることをコンセプトの要件ようけんとして表現ひょうげんできる:

concept InputIterator<typename Iter>
{
  typename value_type;
  typename reference;
  typename pointer;
  typename difference_type;
  require Regular<Iter>;
  require Convertible<reference, value_type>;
  reference operator*(const Iter&); // デリファレンス
  Iter& operator++(Iter&);          // ぜんおけインクリメント
  Iter operator++(Iter&, int);      // おけインクリメント
  // ...
}

コンセプトマップ

編集へんしゅう

コンセプトマップは、コンセプトにかた明示めいじてきむすびつけるのに使つかわれる。これにより、かたが(可能かのうならば)がた定義ていぎえることなくコンセプトに適合てきごうすることをしめせる。れいげる:

concept_map InputIterator<char*>
{
  typedef char value_type;
  typedef char& reference;
  typedef char* pointer;
  typedef std::ptrdiff_t difference_type;
};

このコンセプトマップは、InputIteratorコンセプトをたすかたとしてchar*かたあたえている。

柔軟じゅうなんせいたかめるため、コンセプトマップ自体じたいをテンプレートに出来できる。以下いかれいは、あらゆるポインタがたあつかえるように拡張かくちょうしたものである:

template<typename T> concept_map InputIterator<T*>
{
  typedef T value_type;
  typedef T& reference;
  typedef T* pointer;
  typedef std::ptrdiff_t difference_type;
};

さらに、コンセプトマップは、クラスに共通きょうつう関連付かんれんづけられる関数かんすう定義ていぎなどの構造こうぞうしめす、ミニタイプとしてもうことも出来できる:

concept Stack<typename X>
{
  typename value_type;
  void push(X&, const value_type&);
  void pop(X&);
  value_type top(const X&);
  bool empty(const X&);
};

template<typename T> concept_map Stack<std::vector<T> >
{
  typedef T value_type;
  void push(std::vector<T>& v, const T& x) { v.push_back(x); }
  void pop(std::vector<T>& v) { v. pop_back(); }
  T top(const std::vector<T>& v) { return v. back(); }
  bool empty(const std::vector<T>& v) { return v. empty(); }
};

このコンセプトマップは、Stackコンセプトを実装じっそうするかた引数ひきすうとするテンプレートが、std::vector引数ひきすうれるように定義ていぎしている。std::vector使つかえるようにするため、かく関数かんすうしをstd::vector関数かんすうしにえている。これをもちいれば、究極きゅうきょくてきには、すで存在そんざいするオブジェクトの定義ていぎえることなく、それをテンプレート関数かんすう使用しようするインターフェースに適合てきごうできる。

静的せいてき表明ひょうめいもちいてコンセプトのかく要件ようけん確認かくにんできることもできる。実際じっさいには静的せいてき表明ひょうめい機能きのうべつ問題もんだい焦点しょうてんてているのであるが、この機能きのうでテンプレートのようする要件ようけん検証けんしょうすることができる。

axiomキーワードをもちいて、コンセプトを実装じっそうするかたたすべき性質せいしつ記述きじゅつできる。これはコードの動作どうさには寄与きよせず、コードチェッカIDEへのヒントとしての利用りよう想定そうていされている。[3]

コンセプトによるチェックからの除外じょがい

編集へんしゅう

late_checkキーワードをもちいて、部分ぶぶんてきにコンセプトによるチェックをおこなわないように出来でき[4]

暗黙あんもくのコンセプト

編集へんしゅう

いくつかのコンセプトは、ライブラリの使用しようによらずstd名前なまえ空間くうかんない暗黙あんもく定義ていぎされる[5]

関連かんれんする機能きのう

編集へんしゅう

コンセプトをベースとした機能きのう、およびコンセプトのライブラリも導入どうにゅうされる予定よていであった。コンセプトの削除さくじょはコンセプトを使つかわないように修正しゅうせいされている。修正しゅうせいについてはC++0x参照さんしょう

範囲はんいベースの for ループ

編集へんしゅう

Boost C++ ライブラリでは、いくつか "範囲はんい" のコンセプトを使用しようしているものがある。範囲はんいは、リストのてんをもってリストを表現ひょうげんするものであり、コンテナにもている。順序じゅんじょきのコンテナは範囲はんいコンセプトかられば上位じょういにあり、順序じゅんじょきコンテナからふたつイテレータをってくれば範囲はんい定義ていぎできる。これらのかんがかたや、またこれをもと動作どうさするアルゴリズムが、C++0x の標準ひょうじゅんライブラリにまれる予定よていである。しかし C++0x では、ライブラリだけではなく、範囲はんいコンセプトを使つか言語げんご機能きのうももたらされることになる予定よていである。

for ぶんでは、範囲はんいかんがかたもちいて簡単かんたん反復はんぷくおこなえるようになる:

int my_array[5] = { 1, 2, 3, 4, 5 };
for (int &x : my_array) {
  x *= 2;
}

しん形式けいしきfor ループでは、ひと部分ぶぶんで、範囲はんい反復はんぷくするために使つか変数へんすう定義ていぎする。この変数へんすうは、一般いっぱんfor ループで宣言せんげんされる変数へんすう同様どうよう、ループの範囲はんいにのみスコープをつ。":" につづふた部分ぶぶんで、反復はんぷく対象たいしょう範囲はんい指定していする。この場合ばあい、C スタイルの配列はいれつ範囲はんいコンセプトに変換へんかんするコンセプトマップがあるので、C 配列はいれつ範囲はんいコンセプトとしてわたすことが出来できる。この機能きのうは、 std::vector などの範囲はんいコンセプトをたすものならなににでも適用てきようできる。

コンセプトライブラリ

編集へんしゅう

C++0xにはコンセプトのライブラリが追加ついかされる予定よていであった。

<concepts>

<type_traits>のコンセプトばん。HasPlus(+演算えんざん使つかえる)、DefaultConstructible(デフォルトコンストラクタによる構築こうちく出来できる)などの基本きほんてき性質せいしつあらわすコンセプトがあつめられている。[6]

<container_concepts>

STLコンテナを規定きていするコンセプト。[7]

<iterator_concepts>

イテレータ規定きていするコンセプト。[8]

<memory_concepts>

アロケータ規定きていするコンセプト。[9]

削除さくじょ経緯けいい

編集へんしゅう

今後こんご予定よてい

編集へんしゅう

参考さんこう文献ぶんけん

編集へんしゅう
  1. ^ InformIT, The Removal of Concepts From C++0x Jul 23, 2009. http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=441
  2. ^ Pete Becker, Working Draft, Standard for Programming Language C++, 2009-06-22 コンセプトは14.10せつ http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2914.pdf
  3. ^ N2914 14.10.1.4 Axioms
  4. ^ N2914 6.9 Late-checked block
  5. ^ N2914 14.10.4 Supported concepts
  6. ^ N2914 20.2 Concepts
  7. ^ N2914 23.2.6 Container concepts
  8. ^ N2914 24.2 Iterator concepts
  9. ^ N2914 20.8 Memory