2

型がファンクターかどうかを判断するための特性メタ関数を作成できますか? の SFINAE を使用してファンクターをチェックできるコードはたくさんありdecltype(&T::operator())ます。たとえば、

template<class T>
struct is_functor {
    template<class F>
    static auto test(decltype(&F::operator())) -> std::true_type;
    template<class F>
    static auto test(...) -> std::false_type;
    static constexpr bool value = decltype(test<T>(0))::value;
};

operator()ただし、ジェネリック ラムダはテンプレート関数であるため、これはジェネリック ラムダでは機能しません。

ジェネリック ラムダの引数の型にいくつかの制約を加える、ジェネリック ラムダ バージョンの限定的なケースのコードがいくつかあります。たとえば、ラムダ式にメンバー アクセス操作などの型に対して有効ではない式が含まれている場合、ここでの回答 ( https://stackoverflow.com/a/5117641/2580815 ) は機能しません。int

アリティに一般性は必要ありません。実際、型が 1 つのパラメーターのみを受け入れるファンクターになる可能性があることを知る必要があるだけです。

どうすれば実装できis_functorますか?

使用事例:

指定されたパラメーターがテンプレート関数のファンクターであるかどうかを検証しようとしています。つまり、オーバーロードされたテンプレート関数が必要です。たとえば、次のようになります。

template<class F, class = enable_if_t<is_functor<std::decay_t<F>>::value>>
auto make_func(F &&f) { return std::forward<F>(f); }
template<class F, class = enable_if_t<!is_functor<std::decay_t<F>>::value>>
auto make_func(F &&f) { return [f=std::forward<F>(f)] (auto&&) { return f; }; }
4

2 に答える 2

1

これを行う適切な方法はありません(少なくとも静的な反射が得られるまで)。あなたができる最善のことは、オブジェクトがある程度の信頼で呼び出し可能であることを確認することです:

  1. そのoperator()アドレスを取得してみてください。失敗した場合、オブジェクトは呼び出し不可であるか、operator()オーバーロード/テンプレート化されている可能性があります。

  2. any_typeよく使用される関数のインターフェイスを提供するダミー インスタンスでオブジェクトを呼び出してみてください。これは、そのアリティを推測するのに役立つ場合があります。

  3. すべてが失敗した場合は、ユーザーに何らかの方法でアリティの推定を支援するか、アリティを手動で指定するように強制します。

これにアプローチする 1 つの方法は、deduced_arity一連のタグを使用することです。

namespace deduced_arity
{
    template <std::size_t TS>
    struct deducible_t : std::integral_constant<std::size_t, TS>
    {
    };

    struct undeducible_t
    {
    };

    constexpr undeducible_t undeducible{};
    constexpr deducible_t<1> unary{};
}

また、関数オブジェクトfunction_traitsの正確なアリティを静的に伝えるある種の実装も必要になります。これはBoostにあります。

次に、 の実装any_typeも必要です。

その後、検出イディオムを使用して、次の型特性のようなものを使用して、関数オブジェクト オーバーロードされている可能性があるかどうかを確認できます。

template <typename T>
using is_not_overloaded_impl = decltype(&T::operator());

template <typename T>
using is_not_overloaded =
    std::experimental::is_detected<is_not_overloaded_impl, T>;

if constexpr(...) 次に、 (または他のコンパイル時の分岐メカニズム)のチェーンを使用して、適切な推測を行うことができます-例:

if constexpr(is_not_overloaded<T>{})
{
    // use `function_traits` here
}
else if constexpr(std::is_callable<T(any_type)>{})
{
    return deduced_arity::unary;
}
else if constexpr(/* user manually marked arity */)
{
    /* deal with user-defined deduction helpers */
}
else
{
    return deduced_arity::undeducible;
}
于 2017-02-17T09:47:49.953 に答える