50

混乱を避けるために編集してください:は2 つの引数を受け入れdecltypeません。回答を参照してください。

T次の 2 つの構造体を使用して、コンパイル時に型のメンバー関数の存在を確認できます。

// Non-templated helper struct:
struct _test_has_foo {
    template<class T>
    static auto test(T* p) -> decltype(p->foo(), std::true_type());

    template<class>
    static auto test(...) -> std::false_type;
};

// Templated actual struct:
template<class T>
struct has_foo : decltype(_test_has_foo::test<T>(0))
{};

メンバー関数の存在を確認するときに SFINAE を使用するという考えがあるため、有効でない場合に備えて、 を返す のp->foo()省略記号バージョンのみが定義されています。それ以外の場合、最初のメソッドは for に定義され、 を返します。実際の「切り替え」は、 によって返される型を継承する 2 番目のクラスで発生します。これは、そのようなさまざまなアプローチと比較して、巧妙で「軽量」に見えます。teststd::false_typeT*std::true_typetestis_same

with two 引数はdecltype、式の型を取得するだけだと思っていたので、最初は驚きました。上記のコードを見たとき、「式をコンパイルして、常に秒の型を返すようにしてください。式がコンパイルに失敗した場合は失敗します」のようなものだと思いました (したがって、この特殊化を非表示にします; SFINAE)。

しかし:

次に、このメソッドを使用して、 type に依存する限り、「有効な式である」チェッカーを作成できると考えましたT。例:

...
    template<class T>
    static auto test(T* p) -> decltype(bar(*p), std::true_type());
...

http://ideone.com/dJkLPF

これは、最初のパラメーターとしてa を受け入れるように定義されているstd::true_type場合にのみ(または変換可能である場合など)、つまり、型が定義されているコンテキストで書かれている場合はコンパイルされると思いました。 .barTTbar(*p)pT*

ただし、上記の変更は常にに評価されstd::false_typeます。どうしてこれなの?複雑な別のコードで修正したくありません。期待どおりに機能しない理由を知りたいだけです。明らかにdecltype、2 つの引数を使用すると、私が思っていたものとは異なる動作をします。ドキュメントが見つかりませんでした。どこでも 1 つの表現だけで説明されています。

4

2 に答える 2

47

これはカンマ区切りの式のリストで、型はリストの最後の式の型と同じです。通常、最初の式が有効であることを確認するために使用され (コンパイル可能、SFINAE と考えてください)、2 番目decltypeの式は最初の式が有効な場合に返されるように指定するために使用されます。

于 2013-04-16T18:36:40.540 に答える
18

decltype引数を 2 つ取りません。簡単に言えば、式を引数として持つことができ、コンマ演算子は式を作成する 1 つの方法です。パラグラフ 5.18/1:

[...] コンマで区切られた式のペアは、左から右に評価されます。左の式は破棄値式です (箇条 5)。左の式に関連付けられたすべての値の計算と副作用は、右の式に関連付けられたすべての値の計算と副作用の前に並べられます。結果の型と値は、右側のオペランドの型と値です。結果はその右オペランドと同じ値カテゴリであり、右オペランドが glvalue とビットフィールドの場合はビットフィールドです。右側のオペランドの値が一時的 (12.2) の場合、結果はその一時的です。

したがって:

static_assert(std::is_same<decltype(42, 3.14), double>::value, "Will not fire");
于 2013-04-16T18:36:58.377 に答える