3

タイプbarとがありfooます。次の場合にのみ真となるhas_call_with_arg<>ようなテンプレートクラスを構築するにはどうすればよいですか。has_call_with_arg<bar,foo>::value

bar b;
foo f;
b(f);

コンパイルしますか?私はさまざまな関連する質問(上記のものを含む)を調べて試しました

template<typename Func, typename Arg>
class has_call_with_arg
{
  struct bad {};
  struct test : Func
  {
    template<typename C>
    bad operator()(C const&r);
  };
public:
  static const bool value = 
    !std::is_same<bad, typename std::result_of<test(Arg const&)>::type >::value;
};

しかし、それは機能しませんでした(正しい一致が検出されませんでした)。どうしたの?

4

2 に答える 2

3
template<typename sig, typename functor> struct is_callable;
template<typename Ret, typename... Arg, typename functor> 
struct is_callable<Ret(Arg...), functor> { // partial spec
private:
    struct no {};
public:
    template<typename U> static auto f(std::nullptr_t) -> decltype(std::declval<U>()(std::declval<Arg>()...));
    template<typename U> static no f(...);
    static const int value = std::is_convertible<decltype(f<functor>(nullptr)), Ret>::value;
};

このコンテンツは、この特性の構築を説明するチュートリアル用に作成しました (非可変個形式が最初です)。

于 2013-03-01T18:11:40.273 に答える
2

std::result_of<test(Arg const&)>Arg constへの参照を取り、を返す関数型であるテンプレート パラメータを提供しますtest。そのため、あまり役に立ちませんtypetest

書かれているように、コードが必要であることに注意してください

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

于 2013-03-01T18:18:33.070 に答える