Czy mogę napisać metafunction cechy, aby dowiedzieć się, czy typ jest funktorem, czy nie? Istnieją mnóstwo kodu, które mogą sprawdzić funktor za pomocą Sfinae {X0}}, na przykład,

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;
};

Nie działa jednak dla ogólnej Lambda, ponieważ Generic Lambda operator() to funkcja szablonu.

Istnieją pewne kodeksu dla ograniczonej futerału dla ogólnej wersji Lambda, która dokonuje pewnych ograniczeń na temat argumentu typ generyczny lambda. Na przykład, odpowiedź tutaj (https://stackoverflow.com/a/5117641/2580815) Nie działa, jeśli Empression Lambda zawiera dowolne wyrażenie, które nie mogą być ważne dla typu int, takiego jak operacja dostępu do członka.

Nie potrzebuję żadnej ogólności dla arity. W rzeczywistości muszę tylko znać typ może być funktorem, który akceptuje tylko jeden parametr.

Jak mogę zaimplementować mój is_functor?

Przypadek użycia:

Próbuję potwierdzić, jeśli podany parametr jest funktorem lub nie dla funkcji szablonu, to znaczy, chcę lubić pewne funkcje przeciążonych tempalte, na przykład:

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; }; }
2
xylosper 17 luty 2017, 12:36

1 odpowiedź

Najlepsza odpowiedź

Nie ma właściwego sposobu wykonania tego (przynajmniej dopóki nie otrzymamy refleksji statycznej) . Najlepsze, co możesz zrobić, to sprawdzić, czy obiekt jest wywołany z pewnym stopniem pewności:

  1. Spróbuj uzyskać adres operator(). Jeśli nie powiedzie się, obiekt może być albo bez wywołania lub jego {x1}} może być przeciążony / szablonowany.

  2. Spróbuj zadzwonić do obiektu za pomocą instancji {X0}}, która zapewnia interfejs do powszechnie używanej funkcji. To może pomóc rozdzielić swoją arity.

  3. Jeśli wszystko się nie powiedzie, zmusić użytkownika, jakoś pomoże dedukcji artycznej lub ręcznie określić artyzm.

Jednym ze sposobów, w jaki możesz się zbliżyć, ma deduced_arity zestaw tagów:

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{};
}

Będziesz też potrzebować implementacji function_traits, która określa statycznie dokładnie artycznie obiektu funkcji . Może to być Znaleziono w Boost.

Potem potrzebujesz także Wdrożenie any_type.

Następnie możesz użyć czegoś takiego jak następująca cecha typu, aby sprawdzić, czy obiekt funkcyjny może być przeciążony , używając Idiom wykrywania :

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>;

Następnie możesz użyć łańcucha if constexpr(...) (lub dowolnego innego mechanizmu rozgałęzienia kompilacji) , aby dobrze się domyślić - przykład:

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;
}
1
Vittorio Romeo 17 luty 2017, 09:47