混乱を避けるために編集:
decltype
は2つの引数を受け入れません。回答を参照してください。
次の2つの構造体を使用して、コンパイル時に型T
にメンバー関数が存在するかどうかを確認できます。
_// 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()
が無効な場合は、test
の省略記号バージョンのみが_std::false_type
_が定義されています。それ以外の場合、最初のメソッドは_T*
_に対して定義され、_std::true_type
_を返します。実際の「切り替え」は、test
によって返される型から継承する2番目のクラスで発生します。これは、_is_same
_やそのようなものを使用したさまざまなアプローチと比較して、賢く「軽量」のようです。
2つの引数を持つdecltype
は、式のタイプを取得するだけだと思っていたので、最初は驚きました。上記のコードを見たとき、「式をコンパイルして、常に秒の型を返すようにしてください。式のコンパイルに失敗した場合は失敗します」のようなものだと思いました(したがって、この特殊化を非表示にします; SFINAE)。
だが:
次に、このメソッドを使用して、何らかのタイプT
に依存する限り、「isvalidexpression」チェッカーを記述できると思いました。例:
_...
template<class T>
static auto test(T* p) -> decltype(bar(*p), std::true_type());
...
_
これは、bar
が最初のパラメーターとしてT
を受け入れて定義されている場合(またはT
が変換可能である場合)にのみ、_std::true_type
_を返すと思いました。など)、つまり、p
がタイプ_T*
_で定義されているコンテキストで記述された場合、bar(*p)
がコンパイルされます。
ただし、上記の変更では、常にが_std::false_type
_に評価されます。 これはなぜですか?複雑な別のコードで修正したくありません。思ったように動かない理由を知りたいだけです。明らかに、decltype
と2つの引数は、私が思っていたものとは異なる動作をします。ドキュメントが見つかりませんでした。それはどこでも1つの表現でのみ説明されます。
これはコンマで区切られた式のリストであり、タイプはリストの最後の式のタイプと同じです。これは通常、first式が有効であることを確認するために使用され(コンパイル可能、SFINAEと考えてください)、2番目は、最初の式が有効な場合にdecltype
が返されるように指定するために使用されます。
decltype
は2つの引数を取りません。簡単に言うと、引数として式を使用できます。コンマ演算子は、式を作成する1つの方法です。 5.18/1項による:
[...]コンマで区切られた式のペアは、左から右に評価されます。左の式は破棄された値の式です(第5節)。左の式に関連するすべての値の計算と副作用は、右の式に関連するすべての値の計算と副作用の前にシーケンスされます。 結果の型と値は右オペランドの型と値です;結果は、右のオペランドと同じ値のカテゴリになり、右のオペランドがglvalueとビットフィールドの場合はビットフィールドになります。右のオペランドの値が一時(12.2)の場合、結果はその一時です。
したがって:
static_assert(std::is_same<decltype(42, 3.14), double>::value, "Will not fire");