Подтвердить что ты не робот

Как получить подпись выражения С++ bind (...)

Я пытаюсь написать metafunction с именем signature_of, который, учитывая тип функции (указатель), функтор или лямбда, возвращает свою подпись.

Вот что я до сих пор:

#include <boost/mpl/pop_front.hpp>
#include <boost/mpl/push_front.hpp>
#include <boost/function_types/is_member_function_pointer.hpp>
#include <boost/function_types/function_type.hpp>
#include <boost/function_types/result_type.hpp>
#include <boost/function_types/parameter_types.hpp>

#include <type_traits>

template <typename F>
struct signature_of_member
{
    typedef typename boost::function_types::result_type<F>::type result_type;
    typedef typename boost::function_types::parameter_types<F>::type parameter_types;
    typedef typename boost::mpl::pop_front<parameter_types>::type base;
    typedef typename boost::mpl::push_front<base, result_type>::type L;
    typedef typename boost::function_types::function_type<L>::type type;
};

template <typename F, bool is_class>
struct signature_of_impl
{
    typedef typename boost::function_types::function_type<F>::type type;
};

template <typename F>
struct signature_of_impl<F, true>
{
    typedef typename signature_of_member<decltype(&F::operator())>::type type;
};

template <typename F>
struct signature_of
{
    typedef typename signature_of_impl<F, std::is_class<F>::value>::type type;
};

Это довольно просто, причем большая часть реальной работы выполняется библиотекой boost:: function_types. Общая идея:

  • Использовать std:: is_class для распознавания между встроенными функциями (включая lambdas) и функторы
  • для встроенных типов функций используйте boost:: function_types:: function_type, чтобы получить свою подпись
  • для функторов, получить тип своего оператора(), получить его подпись и разрешить ему удалить параметр "this"

Это работает для встроенных функций:

int f(int);
typedef signature_of<decltype(f)>::type Sig;  // Sig is int(int)

для lambdas:

auto f = [](int) { return 0; }
typedef signature_of<decltype(f)>::type Sig;  // Sig is int(int)

и для функторов:

struct A
{
    int operator()(int);
};
typedef signature_of<A>::type Sig;  // Sig is int(int)

Однако это не работает для выражений bind() (которые являются частным случаем функторов). Если я попробую это:

#include <functional>
int g(int);
typedef signature_of<decltype(std::bind(g, 0))>::type Sig;

Я получаю ошибку компилятора:

In file included from test.cpp:3:0:
signature_of.hpp: In instantiation of 'signature_of_impl<
        _Bind<int (*(int))(int)>, true
    >':
signature_of.hpp:45:74:   instantiated from 'signature_of<
        _Bind<int (*(int))(int)>
    >'
test.cpp:21:52:   instantiated from here
signature_of.hpp:39:74: error: type of '& _Bind<
        int (*)(int)({int} ...)
    >::operator()' is unknown

Проблема заключается в том, что оператор() функтора, возвращаемый bind(), является шаблоном, поэтому его тип не может быть определен.

Можно ли получить сигнатуру выражения bind() другим способом?

4b9b3361

Ответ 1

У вас больше проблем, чем тот факт, что шаблонный оператор() шаблонизирован, он также имеет произвольное количество параметров. Помните, что вы должны иметь возможность ссылаться на результат привязки с любым количеством дополнительных аргументов. Например:

int f(int);

auto bound = boost::bind(f, _2);

bound теперь можно вызывать с любым числом аргументов 2 или более, только вторая фактически пересылается на функцию.

Итак, в основном, как сказал еще один ответ, у этого объекта нет подписи. Его подпись определяется только тем, как она используется.

Ответ 2

Если шаблон шаблонизирован, то он не имеет подписи.