Обнаружение функции объекта (функтора) и лямбда-признаков - PullRequest
7 голосов
/ 01 июня 2011

Как я могу определить тип возвращаемого значения и типы параметров нулевых и унарных указателей на функции, объектов std :: function и функторов (включая лямбды)?

Boost's function_traits и функциональных черт не совсем вытащил меня из коробки, но я готов их дополнить или заменить.

Я мог бы сделать что-то вроде этого:

namespace nsDetail
{
    class Dummy { Dummy(); };
}

template<class Fn> struct FnTraits;

template<class R>
struct FnTraits<R(*)()>
{
    typedef nsDetail::Dummy ParamType;
    typedef R               ReturnType;
    typedef R Signature();
};

template<class R, class P>
struct FnTraits<R(*)(P)>
{
    typedef P ParamType;
    typedef R ReturnType;
    typedef R Signature( P );
};

template<class R>
struct FnTraits< std::function<R()> >
{
    typedef nsDetail::Dummy ParamType;
    typedef R               ReturnType;
    typedef R Signature();
};

template<class R, class P>
struct FnTraits< std::function<R(P)> >
{
    typedef P ParamType;
    typedef R ReturnType;
    typedef R Signature( P );
};

Но как мне специализироваться на функторах / лямбдах?

Обновление: Возможно, что-то похожее на этот ответ на другой вопрос , но переведен с перегрузки на специализацию?

Ответы [ 2 ]

6 голосов
/ 01 июня 2011

Это невозможно в общем случае для функторов, то есть типов классов, использующих operator().Это касается и лямбда-объектов.Рассмотрим случай, когда operator() перегружен:

struct functor {
    double
    operator()(double) const;

    int
    operator()(int) const;
};

typedef function_traits<functor>::result_type result_type;

Каким должен быть result_type?

Обратите внимание, что в качестве обходного пути некоторые протоколы (например, boost::apply_visitor из Boost.Variant)) требуют, чтобы result_type присутствовал в классе, предполагая, что все перегрузки, хотя и допускают различные типы, все возвращают тип, совместимый с этим result_type.

И, конечно, учитывая некоторые типы T0 ... Tn, std::result_of<functor(T0, ..., Tn)>::type дает тип возвращаемого значения, связанный с типами параметров.


В случае, когда присутствует ровно одна перегрузка operator() [1], вы можете взять член operator() ипроверьте, что.

struct not_overloaded {
    double
    operator()(double) const;
};

template<typename T>
struct functor_traits {
    typedef decltype(&T::operator()) type;
};

functor_traits<not_overloaded>::type имеет здесь тип double (not_overloaded::*)(double) const, и, приложив немного усилий, вы сможете извлечь из этого то, что вы хотите.(например, специализация вида Ret (T::*)(Args...) const будет соответствовать этому типу.)

[1]: но функтор может предоставлять функциональность, неявно преобразуя также указатель / ссылку на функцию, так что вы можете пропустить это

1 голос
/ 01 июня 2011
...