Я пытаюсь написать метафункцию с именем 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 для различения встроенных функций (включая лямбда-выражения) и функторов
- для встроенных типов функций, используйте boost :: function_types:: function_type, чтобы получить свою подпись
- для функторов, получить тип их оператора (), получить его подпись и назначить врачу, чтобы удалить параметр "this"
Это работаетдля встроенных функций:
int f(int);
typedef signature_of<decltype(f)>::type Sig; // Sig is int(int)
для лямбд:
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)
Однако, это не работает для привязки () выражения (которые являются частным случаем функторов).Если я попробую это:
#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
Проблема заключается в том, что operator () функтора, возвращаемого функцией bind (), является шаблоном, ипоэтому его тип не может быть определен.
Можно ли получить сигнатуру выражения bind () другим способом?