概念とテンプレート制約の違いは何ですか?


96

C ++の完全な概念の提案とテンプレートの制約(たとえば、Dlangに表示される制約やC ++ 1yの新しいconcepts-liteの提案)の意味上の違いは何ですか?

テンプレートの制約ができないよりも、本格的なコンセプトは何ができるのですか?


2
制約案はこれに入ります。
2013年

4.8 Designing Conceptsを思い出しましたが、実際には、コンセプトがさらに制約を加える方法についてはあまりリストされていません。どちらかと言えば、グーグルの概念は、提案から制約のより良い理解を得た後、簡単に見つけられるいくつかの違いを明らかにするかもしれません。
クリス2013年

IMHOの概念は、「プログラミングの要素」でアレクサンダーステパノフなどから要求されたように、可読性を向上させ、より明確なプログラム機能を提供します。ライトプロポーザルは、現時点で必要とされている奇妙なenable_ifタイプの制約の負担を軽減するための、これに向けた動きにすぎません。ジェネリックプログラミングの方が早いほど良い。
dirvine

回答:


135

次の情報は古くなっています。最新のConcepts Liteドラフトに従って更新する必要があります。

制約案のセクション3では、これについて妥当な範囲で説明しています。

コンセプトの提案は、制約(つまり、concepts-lite)を具体化してより短い時間スケールで実装でき、現在C ++ 14で少なくとも何かを目指していることを期待して、しばらくの間、後回しにされています。制約の提案は、後の概念の定義へのスムーズな移行として機能するように設計されています。制約は概念提案の一部であり、その定義に必要なビルディングブロックです。

ではC ++のためのコンセプトのライブラリの設計、サットンとStroustrup氏は次のような関係を考慮してください。

概念=制約+公理

それらの意味をすばやく要約するには:

  1. 制約-型の静的に評価可能なプロパティに対する述語。純粋に構文上の要件。ドメインの抽象化ではありません。
  2. 公理-真であると想定されるタイプの意味上の要件。静的にはチェックされません。
  3. 概念-引数に関するアルゴリズムの一般的で抽象的な要件。制約と公理の観点から定義されています。

したがって、公理(セマンティックプロパティ)を制約(構文プロパティ)に追加すると、概念が得られます。


Concepts-Lite

concepts-liteの提案は最初の部分である制約のみをもたらしますが、これは本格的な概念に向けた重要かつ必要なステップです。

制約

制約はすべて構文に関するものです。これらは、コンパイル時に型のプロパティを静的に識別する方法を提供するため、構文プロパティに基づいてテンプレート引数として使用される型を制限できます。制約に関する現在の提案では、それらは&&およびのような論理接続詞を使用して命題計算のサブセットで表現され||ます。

実際の制約を見てみましょう:

template <typename Cont>
  requires Sortable<Cont>()
void sort(Cont& container);

ここでは、という関数テンプレートを定義していますsort。新しい追加はrequire句です。require節は、この関数のテンプレート引数にいくつかの制約を与えます。特に、この制約は型が型でContなければならないことを示していSortableます。きちんとしたことは、次のように、より簡潔な形式で記述できることです。

template <Sortable Cont>
void sort(Cont& container);

Sortableこの関数で考慮されていないものを渡そうとすると、推定された型が型でTはないことをすぐに伝える素敵なエラーが表示されSortableます。C ++ 11でこれを実行した場合、関数の内部からスローされた恐ろしいエラーが発生sortし、誰にとっても意味がありません。

制約述語は、タイプ特性と非常に似ています。それらはいくつかのテンプレート引数タイプを取り、それに関するいくつかの情報を提供します。制約は、タイプに関する次の種類の質問に答えようとします。

  1. このタイプには、そのような演算子がオーバーロードされていますか?
  2. これらの型をこの演算子のオペランドとして使用できますか?
  3. このタイプにはそのような特徴がありますか?
  4. この定数式はそれと同じですか?(非型テンプレート引数の場合)
  5. この型には、その型を返すyada-yadaという関数がありますか?
  6. このタイプは、そのように使用されるすべての構文要件を満たしていますか?

ただし、制約は型の特性を置き換えるものではありません。代わりに、彼らは協力して働きます。一部のタイプ特性は、概念の観点から定義できるようになり、一部の概念はタイプ特性の観点から定義できます。

したがって、制約についての重要なことは、1つのイオタのセマンティクスを気にしないことです。制約のいくつかの良い例は次のとおりです。

  • Equality_comparable<T>:タイプに==同じタイプの両方のオペランドがあるかどうかをチェックします。

  • Equality_comparable<T,U>==指定された型の左と右のオペランドを持つかどうかを確認します

  • Arithmetic<T>:型が算術型かどうかを確認します。

  • Floating_point<T>:型が浮動小数点型かどうかを確認します。

  • Input_iterator<T>:入力イテレータがサポートする必要がある構文演算を型がサポートするかどうかを確認します。

  • Same<T,U>:指定されたタイプが同じかどうかを確認します。

GCCの特別なconcepts-liteビルドでこれらすべてを試すことができます。


Beyond Concepts-Lite

今、私たちはconcepts-liteの提案を超えてすべてに入ります。これは未来そのものよりもさらに未来的です。これからのすべてがかなり変化する可能性があります。

公理

公理はすべて意味論です。それらは、関係、不変条件、複雑性の保証、その他のことを指定します。例を見てみましょう。

一方でEquality_comparable<T,U>制約があることを教えてくれますoperator== タイプをとるTU、それはあなたが何をその操作は教えてくれない手段。そのためには、公理がありEquivalence_relationます。この公理は、これらの2つのタイプのオブジェクトを比較するとことを言うoperator==与えtrue、これらのオブジェクトは等価です。これは冗長に見えるかもしれませんが、確かにそうではありません。operator==代わりにのように動作するを簡単に定義できますoperator<。あなたはそれをするのは悪いことですが、そうすることができます。

別の例はGreater公理です。タイプの2つのオブジェクトT>and <演算子で比較できると言ってもいいのですが、それらはどういう意味ですか?Greater公理は、IFFはと言うxその後、大きいyそして、y以下ですx。このような公理の提案された仕様は次のようになります。

template<typename T>
axiom Greater(T x, T y) {
  (x>y) == (y<x);
}

したがって、公理は次のタイプの質問に答えます。

  1. これらの2つのオペレーターは互いにこの関係を持っていますか?
  2. このようなタイプのこの演算子はこれを意味しますか?
  3. そのタイプのこの操作はこの複雑さを持っていますか?
  4. その演算子のこの結果は、これが真実であることを意味しますか?

つまり、型のセマンティクスとそれらの型に対する操作に完全に関係しています。これらのものを静的にチェックすることはできません。これをチェックする必要がある場合、型は何らかの形で、これらのセマンティクスに準拠していることを宣言する必要があります。

公理のいくつかの一般的な例を以下に示します。

  • Equivalence_relation:2つのオブジェクトが比較する場合==、それらは同等です。

  • Greater:たびx > y、それからy < x

  • Less_equal:たびx <= y、それから!(y < x)

  • Copy_equalityxおよびyのタイプT:ifの場合x == y、コピー構築によって作成された同じタイプの新しいオブジェクトでありT{x} == y、それでもx == y(つまり、非破壊的です)。

概念

現在、コンセプトの定義は非常に簡単です。それらは単に制約と公理の組み合わせです。これらは、型の構文とセマンティクスに対する抽象的な要件を提供します。

例として、次のOrdered概念を検討してください。

concept Ordered<Regular T> {
  requires constraint Less<T>;
  requires axiom Strict_total_order<less<T>, T>;
  requires axiom Greater<T>;
  requires axiom Less_equal<T>;
  requires axiom Greater_equal<T>;
}

最初に、テンプレートタイプがTになるOrderedためには、Regularコンセプトの要件も満たしている必要があります。Regularコンセプトは、タイプが行儀であることを非常に基本的な要件である-それは、構築され破壊され、コピーし、比較することができます。

これらの要件に加えて、1つの制約と4つの公理OrderedT満たす要件:

  • 制約:Orderedタイプにはが必要operator<です。これは静的にチェックされるため、存在する必要あります。
  • 公理:用xyタイプのT
    • x < y 厳密な合計順序を示します。
    • 場合xよりも大きいyy未満でありx、そして逆もまた同様です。
    • xがより小さいか等しい場合、は未満yyはなくx、その逆も同様です。
    • 場合x以上に等しくyyより大きくないx、そして逆もまた同様です。

このように制約と公理を組み合わせると、概念がわかります。これらは、アルゴリズムで使用するための抽象型の構文要件と意味要件を定義します。アルゴリズムは現在、使用される型が特定の操作をサポートし、特定のセマンティクスを表現すると想定する必要があります。コンセプトがあれば、要件を確実に満たすことができます。

では、最新のコンセプト設計、コンパイラは概念のみの構文の要件はテンプレート引数によって満たされていることを確認します。公理はチェックされません。公理は静的に評価できない(または完全にチェックできないことが多い)セマンティクスを表すため、型の作成者は、その型が概念のすべての要件を満たしていることを明示的に述べる必要があります。これは以前の設計ではコンセプトマッピングとして知られていましたが、その後削除されました。

以下に概念の例をいくつか示します。

  • Regular タイプは構成可能、破壊可能、コピー可能であり、比較することができます。

  • Ordered型はをサポートしoperator<、厳密な合計順序とその他の順序のセマンティクスを持っています。

  • Copyable種類は破壊可能、構築可能にコピーされ、そして場合xISに等しいyxコピーされ、コピーも等しく比較されますy

  • Iteratorタイプが関連付けられている必要がありますタイプはvalue_typereferencedifference_type、およびiterator_category自身が特定の概念を満たしていなければなりません。また、それらはサポートされoperator++、逆参照可能でなければなりません。

コンセプトへの道

制約は、C ++の完全な概念機能に向けた最初のステップです。これらは、静的な実施が可能な型の要件を提供するため、非常に重要なステップです。これにより、よりクリーンなテンプレート関数とクラスを作成できます。これstd::enable_ifで、メタプログラミングの友達の困難と醜さのいくつかを回避できます。

ただし、制約の提案では行われないことがいくつかあります。

  1. 概念定義言語は提供していません。

  2. 制約は概念マップではありません。ユーザーは、特定の制約を満たすようにタイプに特別な注釈を付ける必要はありません。それらは静的にチェックされ、使用される単純なコンパイル時言語機能です。

  3. テンプレートの実装は、テンプレート引数の制約によって制約されません。つまり、関数テンプレートが制約された型のオブジェクトに対して実行してはならない処理を行う場合、コンパイラーはそれを診断する方法がありません。完全に機能するコンセプトの提案はこれを行うことができます。

制約案は、完全な概念案をその上に導入できるように特別に設計されています。運が良ければ、その移行はかなりスムーズなはずです。概念グループは、C ++ 14(または直後の技術レポート)に制約を導入しようとしていますが、C ++ 17の周りには完全な概念が登場する可能性があります。


5
concepts-liteはテンプレート自体の実装に対する制約をチェックしないことに注意してください。したがって、任意のDefaultConstructableを使用できると主張することはできますが、コンパイラーが誤ってコピーコンストラクターを使用することを妨げることはありません。より完全な機能を備えたコンセプトの提案はそうでしょう。
Nicol Bolas 2013年

24
それ最初のドラフトですか?
Nicol Bolas 2013年

2
@sftrabbit、非常に良い答え。しかし、私は質問があります。型が概念のセマンティック要件を満たしていることをコンパイラがどのようにチェックするのでしょうか。
Rayniery 2013年

1
(多くの不確実性がある場合)実行時に「公理」がチェックされますか、それとも一種のプロミスタグとしてのみ機能しますか?
赤いXIII

4
@ScarletAmaranth:結局、有限の限られた時間で定理を自動的に証明するためです。これには2つの障害があります。1.理論上非常に困難であり、現在の技術では不可能である有限の有界時間で定理を証明する。2.証明が他の公理に基づいていない限り、公理を証明することはできません。(その場合、数学的には「公理ではない」になります)これらの公理は、コンパイラーに「もちろん、有用だと思われる場合は比較を元に戻すことができます...」、または「はい、常に交差で使用される空のセット」を伝えることを目的としています同じ結果が得られます。」
Laurent LA RIZZA 2013年


4

私の2セント:

  1. concepts-liteの提案は、テンプレート実装の「型チェック」を行うことを意図したものではありません。つまり、Concepts-liteは、テンプレートのインスタンス化サイトで(概念的に)インターフェースの互換性を保証します。論文からの引用:「concepts liteは、述語を使用してテンプレート引数を制約できるようにするC ++の拡張機能です。」以上です。テンプレート本体が述語に対して(単独で)チェックされるとは言いません。これは、concepts-liteについて話しているときに、アーチタイプのファーストクラスの概念がないことを意味します。archtypesは、私が正しく覚えているとしたら、コンセプトが多い提案では、テンプレートの実装を満たすために提供されるタイプが少なくない、または増えないタイプです。

  2. concepts-liteは、コンパイラによってサポートされている少しの構文トリックを備えた栄光のあるconstexpr関数を使用しています。検索ルールに変更はありません。

  3. プログラマーは概念マップを作成する必要はありません。

  4. 最後に、「制約の提案は、仕様やセマンティクスの使用に直接対処するものではありません。構文のチェックのみを目的としています。」つまり、公理は範囲内にありません(これまでのところ)。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.