获取 C++ 函数参数的类型

Get types of C++ function parameters

是否有标准方法获取函数参数的类型并将这些类型作为模板参数包传递?我知道这在 C++ 中是可能的,因为 it has been done before.

我希望在 C++14 或即将推出的 C++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>...>();
}

需要明确的是,声称没有标准方法可以做到这一点的答案不是答案。如果没有答案,我宁愿在将解决方案添加到 C++500 或直到宇宙热寂之前(以较早发生者为准),问题仍未得到解答:)

编辑:删除的答案指出我可以使用 PRETTY_FUNCTION 来获取参数类型的名称。但是,我想要实际类型。不是那些类型的名称。

此语法略有不同。

首先,因为类型比包更容易使用,类型包含一个包。 using type=types; 只是节省了我在生成 types:

的代码中的工作
template<class...>struct types{using type=types;};

这是主力军。它接受一个签名,并生成一个包含签名参数的 types<?...> 包。 3 个步骤,我们可以获得漂亮干净的 C++14 式语法:

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...,而是取 types<Params...>。这类似于 "tag dispatching" 模式,我们利用模板函数类型推导将参数移动到类型列表中:

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

我的 fopen 不一样,因为我不想打扰 #includeing 东西:

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

并且语法不是基于 fopen,而是 fopen 类型 。如果你有一个指针,你需要做 decltype(*func_ptr) 或类似的事情。或者我们可以增加顶部以处理 R(*)(Args...) 以便于使用:

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

live example.

请注意,这 不适用于 重载函数,也不适用于函数对象。

一般来说,这种事情是个坏主意,因为通常你知道你是如何与一个对象交互的。

只有当您想获取一个函数(或函数指针)并将一些参数从某处的堆栈中弹出并根据预期的参数或类似的东西调用它时,以上内容才有用。

使用Boost.FunctionTypes and std::index_sequence. Below is an example which prints the argument types of the function func. You can change the doit static function to do what you want. See it in action here.

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;
}

Headers(在此处向下移动以减少上述代码片段中的噪声):

#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;

对于提升用户,#include <boost/type_traits.hpp>

boost::function_traits<decltype(function)>::arg1_type
boost::function_traits<decltype(function)>::arg2_type
// boost::function_traits<decltype(function)>::argN_type

using FopenArg1 = boost::function_traits<decltype(fopen)>::arg1_type;
using FopenArg2 = boost::function_traits<decltype(fopen)>::arg2_type;
void some_function(FopenArg1, FopenArg2);

Boost Document

受@Yakk 的启发,这里有一个稍微简化的版本:

  1. 首先我们定义辅助元函数来将函数参数类型存储为元组。
template<typename Sig>
struct signature;

template<typename R, typename ...Args>
struct signature<R(Args...)>
{
    using type = std::tuple<Args...>;
};
  1. 我们使用概念来限制输入为函数
template<typename F>
concept is_fun = std::is_function_v<F>;
  1. 这是我们的函数“arguments”,用于检索输入的参数类型。取决于输入参数,我们重载“arguments”函数以接受引用和非引用。(自由函数总是通过引用传递。我们甚至不必有函数体,只有 return类型就足够了,因为这是元函数。
template<is_fun F>
auto arguments(const F &) -> typename signature<F>::type;
  1. 这里是测试:
void foo(const string &, int, double)
{}

static_assert(std::is_same_v<decltype (arguments(foo)), 
                             std::tuple<const string &, int, double>>);

我的 full-fledged 版本是 here which also supports lambda, functor, member function pointer