Получить аргументы функции как кортеж в C ++ - PullRequest
7 голосов
/ 22 ноября 2011

Предположим, у меня есть объявления функций, подобные этим:

void foo(int x, float y);

class X {
  void anotherFoo(double a, int c);
};

Как я могу получить кортеж, который соответствует аргументам функции?В приведенном выше случае это будет:

boost::tuple<int, float>
boost::tuple<X*, double, int>

или даже лучше с типом результата в качестве 0-го элемента:

boost::tuple<void, int, float>
boost::tuple<void, X*, double, int>

Я знаю, что boost::function_types::parameter_types может сделать именно это.Однако меня интересует принцип его реализации.

Ответы [ 2 ]

9 голосов
/ 22 ноября 2011

Вы можете получить кортеж type , соответствующий вашему аргументу types , например:

template <typename R, typename... T>
std::tuple<T...> function_args(R (*)(T...))
{
    return std::tuple<T...>();
}

// get the tuple type
typedef decltype(function_args(foo)) FooArgType;
// create a default-initialised tuple
auto args = function_args(foo);

Это то, что вы хотите? Обратите внимание, что вам может потребоваться добавить одну или несколько перегрузок function_args, например. принятие параметра типа класса для методов класса.

2 голосов
/ 30 ноября 2011

Наконец-то нашли способ сделать это в C ++ 03, используя частичную специализацию. Необходимы многочисленные перегрузки для различного числа аргументов и константных / volatile функций, но идея заключается в следующем:

/* An empty template struct, this gets chosen if the given template parameter is not a member function */
template <typename _Func>
struct MemberFunctionInfo {  };

/* Specialization for parameterless functions */
template <typename _Result, typename _Class>
struct MemberFunctionInfo<_Result (_Class::*) ()>  {
    typedef _Class class_type;
    typedef _Result result_type;
    typedef boost::tuple<> parameter_types;
    enum { arity = 0 };
};

/* Specialization for parameterless const functions */
template <typename _Result, typename _Class>
struct MemberFunctionInfo<_Result (_Class::*) () const> : MemberFunctionInfo<_Result (_Class::*) ()> { };

/* Specialization for functions with one parameter */
template <typename _Result, typename _Class, typename P0>
struct MemberFunctionInfo<_Result (_Class::*) (P0)>  {
    typedef _Class class_type;
    typedef _Result result_type;
    typedef boost::tuple<P0> parameter_types;
    enum { arity = 1 };
};

/* Specialization for const functions with one parameter */
template <typename _Result, typename _Class, typename P0>
struct MemberFunctionInfo<_Result (_Class::*) (P0) const> : MemberFunctionInfo<_Result (_Class::*) (P0)> { };

.
.
.

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

template <typename MemFunc>
int getArity(MemFunc fn)  {
  // Can also use MemberFunctionInfo<MemFunc>::parameter_types with boost::mpl
  return MemberFunctionInfo<MemFunc>::arity;
}

Приведенное выше решение имеет некоторые недостатки. Он не обрабатывает ссылки на функции, функции, не являющиеся членами или volatile / const volatile функций-членов, но их легко учесть, добавив больше специализаций.

Для C ++ 11 подход, упомянутый @Useless, намного чище и должен быть предпочтительным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...