2015-12-15 11 views
11

私はSVNのGCCでliteという概念を試してきました。私は、私の理解が不足していると思われる問題にぶつかりました。誰かが私を正しい方向に向けることができれば感謝します。私のコードは次のとおりです。ここで 概念と宣言の順序

#include <iostream> 
#include <string> 

// Uncomment this declaration to change behaviour 
//void draw(const std::string&); 

template <typename T> 
concept bool Drawable() { 
    return requires (const T& t) { 
     { draw(t) } 
    }; 
} 

void draw(const std::string& s) 
{ 
    std::cout << s << "\n"; 
} 

int main() 
{ 
    static_assert(Drawable<std::string>()); // Fails 
} 

私はタイプ const T&のパラメータ、機能 draw(t)コンパイルを与えることを要求することを意図しているシンプルなコンセプト、 Drawableを定義します。

次に、coutに文字列を "描画"する関数draw(const std::string&)を定義します。最後に、static_assertが呼び出されたときに、適切なdraw()関数が有効なので、がDrawableのコンセプトと一致するかどうかを確認します。

draw(const std::string&)の前に宣言が含まれていなければ、静的なアサートは失敗します。の概念定義がありません。理由はわかりません。

これはコンセプト上の動作ですか、何か間違っていますか?

+8

何百ものダブがあるBog標準のADL問題。関連する型のどれもメンバーではないため、ADLはグローバル名前空間を検査しません。テンプレートの上の宣言のコメントを外すと、unqualified-name-lookupがテンプレート定義コンテキストでそれを見つけることができます。 – Columbo

+0

したがって、彼が名前空間stdにそのvoid draw宣言を置くと、それは動作するはずです。 – West

+0

開始文にSVNリファレンスがありません。それはどんな意味でも重要なのでしょうか? –

答えて

-1

上記の関数は、それを使用するすべての関数がそれについて知る必要があるように宣言する必要があるためです。

クラスでは、関数はヘッダーファイルで宣言されています。メンバーでない場合は、使用する前に宣言する必要があります。これは、コンパイラが上から下に読み込み、宣言を見たときに関数を知るためです。

コンセプトコードと描画コードを入れ替えると、それもうまくいくはずです。

1

問題はADLとは関係ありませんが、名前検索のみで問題になります。 GCCが使用するコンセプトドラフトはn4377ですが、私が使用するC++標準ドラフトはn4140です。まず、スタンダードにダイビングする前に、私たちが知っている形のMCVEにあなたの問題を変えることができます。とすれば、となります。例:

template<typename T> concept bool C = 
    requires (T a, T b) { 
    a + b; 
    }; 

これは簡単な要件です。[expr.prim.req.simple]は、式の妥当性をチェックします。

template<typename T> concept bool Drawable = 
    requires (const T& x) { 
    draw(x); 
    }; 

私たちの例文は次の書式に一致するように書いてあります。 OK、n4377とは何ですか?

[expr.prim.req]/1 A 必要発現は、テンプレート引数に Expressの要件に簡潔な方法を提供します。要件 は、名前検索(3.4)またはタイプ と式のプロパティをチェックすることでチェックできます。

[expr.prim.req]/6要件本体は、 の要件のシーケンスで構成されています。これらの要件は、ローカルパラメータ、 テンプレートパラメータ、および の囲むコンテキストから表示される他の宣言を参照することがあります。 ...

意味があります。 のコンテキストを把握していますはグローバルな名前空間ですので、n4140とは何ですか?3.4.1に記載されている全ての場合において

[basic.lookup.unqual]/1は、スコープ は、それぞれのカテゴリの各々に列挙された順番に宣言するために検索されます。名前の検索は、名前の宣言が であるとすぐに終了します。宣言が見つからない場合、プログラムは です。

名前空間Nのメンバーである関数の 宣言子-IDは(ここで、のみ説明の目的のために、Nグローバルスコープを表すことができる) を宣言しなければならない次の関数の定義に使用される名前ブロックでの使用は、それが使用されるか、またはされる前 その外側のブロック(6.3)、またはのいずれかで、関数の概念のappertainsとして

... 名前空間Nでの使用前に宣言されなければなりません、上記の段落適用されます。