std::result_of<test(Arg const&)>
Arg const
への参照を取り、を返す関数型であるテンプレート パラメータを提供しますtest
。そのため、あまり役に立ちませんtype
。test
書かれているように、コードが必要であることに注意してください
bar b;
foo f;
b(f);
有効であるためには、実際には 5 つの要件が bar
あります。foo
それぞれに、アクセス可能なデフォルトのコンストラクタとデストラクタb(f)
があり、有効な式です。最後の 1 つだけに焦点を当てます (これが意味するところのすべてです)。本当に他の部分を意味する場合は、標準<type_traits>
のプロパティを使用してそれらを追加できます。
この関数std::declval
は、特定のタイプのオブジェクトを持っていなくても、持っているふりをするのに最適です。決して呼び出されてはならないため、通常はdecltype
式の中でのみ使用されます。
SFINAE トリックを成功させるには、次の 2 つの基本的な方法があります。これは、C++ でテンプレート引数推定の失敗が失敗した宣言を破棄できるようにする 2 つの場所に基づいています。
まず、クラスの部分的な特殊化を一致させようとしています:
template<typename Func, typename Arg, typename Enable = void>
struct has_call_with_arg1 : public std::false_type {};
template<typename Func, typename Arg>
struct has_call_with_arg1<Func, Arg,
decltype(std::declval<Func&>()(std::declval<Arg&>()))>
: public std::true_type {};
次に、少なくとも 1 つのオーバーロードが関数テンプレートである場合のオーバーロードの解決。(クラス テンプレートの非テンプレート メンバー関数は、ここでは機能しません。クラスをインスタンス化するには、各メンバー宣言が有効である必要があるためです。)
namespace has_call_with_arg_impl {
template<typename F, typename A>
std::true_type test(decltype(std::declval<F&>()(std::declval<A&>()))*);
template<typename F, typename A>
std::false_type test(...);
}
template <typename Func, typename Arg>
struct has_call_with_arg2
: public decltype(has_call_with_arg_impl::test<Func,Arg>(nullptr)) {};
デモ: http://ideone.com/KgRI8y