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

Nav*_*vin 16 c++ templates variadic-templates c++14 c++17

是否有一种标准方法来获取函数参数的类型并将这些类型作为模板参数包传递?我知道这在C++中是可行的,因为它之前已经完成了.

我希望用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>...>();
}
Run Code Online (Sandbox Code Playgroud)

需要明确的是,一个声称没有标准方法可以做到这一点的答案不是答案.如果没有答案,我希望问题仍然无法解决,直到解决方案被添加到C++ 500或直到宇宙的热量死亡,以先发生者为准:)

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

Yak*_*ont 14

这种语法略有不同.

首先,因为类型比包更容易使用,包是一种类型.将using type=types;只是保存了我在生成代码的工作types:

template<class...>struct types{using type=types;};
Run Code Online (Sandbox Code Playgroud)

这是主力.它需要一个签名,并生成一个types<?...>包含签名参数的包.3个步骤,所以我们可以得到很好的干净的C++ 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;
Run Code Online (Sandbox Code Playgroud)

这是语法差异.Params...我们采取的不是直接采取types<Params...>.这类似于"标签调度"模式,我们利用模板函数类型推导将参数移动到类型列表中:

template <class...Params>
void some_function(types<Params...>) {
}
Run Code Online (Sandbox Code Playgroud)

fopen的不同,因为我不想打扰#include东西:

void* fopen(const char* filename, const char* mode);
Run Code Online (Sandbox Code Playgroud)

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

int main(){
  some_function(args_t<decltype(fopen)>{});
}
Run Code Online (Sandbox Code Playgroud)

实例.

请注意,这并不会与重载函数工作,也不与功能对象.

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

如果你想获取一个函数(或函数指针)并从某个堆栈中的某个堆栈中弹出一些参数并根据它预期的参数调用它,或者类似的东西,上面只会有用.

  • "在一些堆栈中弹出一些参数并根据它预期的参数调用它".嗯,这正是我在做的! (2认同)
  • 成员“using type=types”有什么用? (2认同)

Nic*_*ang 8

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

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

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

static_assert(std::is_same_v<decltype (arguments(foo)), 
                             std::tuple<const string &, int, double>>);
Run Code Online (Sandbox Code Playgroud)

我的完整版本在这里,它还支持 lambda、仿函数、成员函数指针


Pra*_*han 5

使用Boost.FunctionTypesstd::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;
}
Run Code Online (Sandbox Code Playgroud)

标题(移至此处以减少上述代码片段中的噪音):

#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;
Run Code Online (Sandbox Code Playgroud)

  • 加上 Boost.TypeIndex ,你会得到一个非常可读的结果 - http://coliru.stacked-crooked.com/a/d9af42b0a48dc867 (4认同)