Получить типы параметров функции С++

Есть ли стандартный способ получить типы аргументов функции и передать эти типы в виде пакета параметров шаблона? Я знаю, что это возможно в С++, потому что это было сделано до.

Я надеялся, что с С++ 14 или предстоящим С++ 1z будет существовать идиоматический способ реализовать arg_types<F>... здесь:

template <typename ...Params>
void some_function(); // Params = const char* and const char*

FILE* fopen(const char* restrict filename, const char* restrict mode);

int main(){
    some_function<arg_types<fopen>...>();
}

Чтобы быть ясным, ответ, утверждающий, что нет стандартного способа сделать это, не является ответом. Если ответа нет, я бы предпочел, чтобы этот вопрос оставался без ответа до тех пор, пока решение не будет добавлено в С++ 500 или до жары смерти Вселенной, в зависимости от того, что произойдет раньше:)

Изменить: удаленный ответ отметил, что я могу использовать PRETTY_FUNCTION для получения имен типов параметров. Тем не менее, мне нужны фактические типы. Не имена этих типов.

Ответ 1

Этот синтаксис несколько отличается.

Во-первых, поскольку типы легче работать с пакетами, тип, в котором содержится пакет. using type=types; просто сохраняет работу в коде, который генерирует types:

template<class...>struct types{using type=types;};

Вот рабочая лошадка. Он принимает сигнатуру и создает пакет types<?...>, содержащий аргументы для сигнатуры. 3 шага, чтобы мы могли получить хороший чистый синтаксис С++ 14esque:

template<class Sig> struct args;
template<class R, class...Args>
struct args<R(Args...)>:types<Args...>{};
template<class Sig> using args_t=typename args<Sig>::type;

Вот синтаксическая разница. Вместо прямого принятия Params... возьмем a types<Params...>. Это похоже на шаблон "диспетчеризация тегов", где мы используем вывод типа функции шаблона для перемещения аргументов в список типов:

template <class...Params>
void some_function(types<Params...>) {
}

Мой fopen отличается, потому что я не хочу беспокоиться #include ing stuff:

void* fopen(const char* filename, const char* mode);

И синтаксис не основан на fopen, а тип fopen. Если у вас есть указатель, вам нужно сделать decltype(*func_ptr) или somesuch. Или мы могли бы увеличить верхнюю часть для обработки R(*)(Args...) для удобства использования:

int main(){
  some_function(args_t<decltype(fopen)>{});
}

живой пример.

Обратите внимание, что это не работает с перегруженными функциями и не работает с объектами функций.

В общем, такая вещь - плохая идея, потому что обычно вы знаете, как вы взаимодействуете с объектом.

Выше было бы полезно, если бы вы захотели взять функцию (или указатель на функцию) и вытащить некоторые аргументы из некоторого стека где-нибудь и называть ее исходя из ожидаемых параметров или чего-то подобного.

Ответ 2

Используйте Boost.FunctionTypes и std::index_sequence. Ниже приведен пример, который печатает типы аргументов функции func. Вы можете изменить статическую функцию doit, чтобы делать то, что вы хотите. См. Это в действии здесь.

template <typename FuncType>
using Arity = boost::function_types::function_arity<FuncType>;

template <typename FuncType>
using ResultType = typename boost::function_types::result_type<FuncType>::type;

template <typename FuncType, size_t ArgIndex>
using ArgType = typename boost::mpl::at_c<boost::function_types::parameter_types<FuncType>, ArgIndex>::type;

void func(int, char, double) {}

template <typename Func, typename IndexSeq>
struct ArgPrintHelper;

template <typename Func, size_t... Inds>
struct ArgPrintHelper<Func, integer_sequence<size_t, Inds...> >
{
  static void doit()
  {
    string typeNames[] = {typeid(ResultType<Arg>).name(), typeid(ArgType<Func, Inds>).name()...};
    for (auto const& name : typeNames)
      cout << name << " ";
    cout << endl;
  }
};

template <typename Func>
void ArgPrinter(Func f)
{
  ArgPrintHelper<Func, make_index_sequence<Arity<Func>::value> >::doit();
}

int main()
{
  ArgPrinter(func);
  return 0;
}

Заголовки (перемещаются вниз, чтобы уменьшить шум в приведенном выше фрагменте кода):

#include <boost/function_types/function_type.hpp>
#include <boost/function_types/parameter_types.hpp>
#include <boost/function_types/result_type.hpp>
#include <boost/function_types/function_arity.hpp>

#include <algorithm>
#include <iostream>
#include <string>
#include <type_traits>
#include <typeinfo>
#include <tuple>
#include <utility>
using namespace std;