Получить тип аргументов функции как кортеж

Проблема

Учитывая любую функцию (или вызываемый) типа Function, как я могу получить все ее типы аргументов как тип кортежа?

Например, мне нужен трейт function_traits<Function>::arguments, где:

int f();
typename function_traits<decltype(f)>::arguments // => gives me std::tuple<>

void g(int);
typename function_traits<decltype(g)>::arguments // => gives me std::tuple<int>

void h(int, int);
typename function_traits<decltype(h)>::arguments // => gives me std::tuple<int, int>

Моя мысль

Первый

Мне нужно получить размер аргументов, к счастью, boost уже реализовал function_traits<F>::arity

затем

Создайте std::integer_sequence из 1 для artify, сопоставьте его с типом аргументов, но здесь возникает проблема, чтобы сопоставить integer_sequence, мне нужно что-то вроде этого:

function_traits<F>::arg_type<N> // -> N-th arg_type

но boost обеспечивает только это:

function_traits<F>::argN_type

Вопрос

Как я могу реализовать function_traits<F>::arg_type<N>? Я могу использовать стандарт С++ до С++ 17


person Zang MingJie    schedule 23.08.2019    source источник


Ответы (2)


Что-то вроде этого:

#include <tuple>

template<typename x_Function> class
function_traits;

// specialization for functions
template<typename x_Result, typename... x_Args> class
function_traits<x_Result (x_Args...)>
{
    public: using arguments = ::std::tuple<x_Args...>;
};

пример использования:

#include <type_traits>

int foo(int);

using foo_arguments = function_traits<decltype(foo)>::arguments;
static_assert(1 == ::std::tuple_size<foo_arguments>::value);
static_assert(::std::is_same_v<int, ::std::tuple_element<0, foo_arguments>::type>);

онлайн-компилятор

person user7860670    schedule 23.08.2019
comment
Как это работает ? Все использование сведется к первому типу, который вообще не реализован, ко второму никогда не сведется. - person Zang MingJie; 23.08.2019
comment
@ZangMingJie Специализация шаблона является точным совпадением и более специализирована, чем общий шаблон. Поэтому использование с функцией сведется ко второму типу. - person Konrad Rudolph; 23.08.2019
comment
@ZangMingJie Я добавил пример использования - person user7860670; 23.08.2019
comment
возможно ли заставить его работать с лямбдой? или любой вызываемый и функтор? - person Zang MingJie; 23.08.2019
comment
@ZangMingJie Для этого потребуется выяснить аргументы функции-члена operator (). Это может быть нетривиально, если operator () перегружен - person user7860670; 23.08.2019
comment
после добавления функции-члена reduce и этого template<typename Class> class function_traits<Class> : public function_traits<decltype(&Class::operator())> {}; он работает с лямбдой без автоматических аргументов. - person Zang MingJie; 23.08.2019

Уже поздно играть?

Вы можете использовать C++17, так что... как насчет использования std::function руководств по дедукции?

template <typename T>
struct function_traits
 {
   template <typename R, typename ... As>
   static std::tuple<As...> pro_args (std::function<R(As...)>);

   using arguments = decltype(pro_args(std::function{std::declval<T>()}));
 };

Ниже приведен полный пример компиляции

#include <tuple>
#include <functional>
#include <type_traits>

int f ();
void g (int);
void h (int, int);

template <typename T>
struct function_traits
 {
   template <typename R, typename ... As>
   static std::tuple<As...> pro_args (std::function<R(As...)>);

   using arguments = decltype(pro_args(std::function{std::declval<T>()}));
 };

int main ()
 {
   static_assert(std::is_same_v<std::tuple<>,
                 function_traits<decltype(f)>::arguments>);

   static_assert(std::is_same_v<std::tuple<int>,
                 function_traits<decltype(g)>::arguments>);

   static_assert(std::is_same_v<std::tuple<int, int>,
                 function_traits<decltype(h)>::arguments>);
 }
person max66    schedule 23.08.2019
comment
std::function требует копирования, а не все вызываемые объекты копируются - person Zang MingJie; 23.08.2019
comment
Просто безуспешно связал этот пример rextester.com/EUHA75064 (c++17 включен) - person Dewfy; 31.03.2021
comment
@Dewfy - это проблема поддержки clang C ++ 17: пока clang 9 не выдает ошибку, начиная с clang 10 компилируется без проблем. - person max66; 31.03.2021