【问题标题】:Retrieve function arguments as a tuple in C++在 C++ 中将函数参数作为元组检索
【发布时间】:2011-11-22 09:37:27
【问题描述】:

假设我有这样的函数声明:

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 可以做到这一点。不过,我对它的实现原理很感兴趣。

【问题讨论】:

  • 我会使用struct。使用元组的目的/优势是什么?
  • @kol 减少样板代码,减少噪音
  • 您的意思是要在编译时或运行时自动生成元组类型,还是要从 regs / stack 中提取参数,或两者兼而有之,还是其他?跨度>
  • 它应该是所有编译时间 - 我只需要作为结构/元组的参数,以便我可以在元编程中使用它们。
  • 您是否尝试过阅读提升资源?

标签: c++ function tuples


【解决方案1】:

你可以得到与你的参数types对应的元组type,像这样:

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 重载,例如。为类方法获取类类型参数。

【讨论】:

  • 如果函数不能被实例化,decltype 是否仍然有效,因为它的一个或多个参数类型不能被默认初始化?如果没有,是否有一些解决方法可以使用指针?
  • 你仍然可以在 typedef 中使用decltype(function_args(foo)),但在这种情况下你永远不能真正调用 function_args
  • 这行得通,谢谢。有没有办法避免 decltype (因为这只是 C++11)? Boost 甚至可以在非 C++11 编译器上工作,所以这应该是可以实现的。
  • 我猜你可以返回一个带有元组类型定义的帮助类实例:那么你只是使用模板函数类型推导来节省写出帮助类类型参数。请注意,可变参数模板语法也仅适用于 C++11 - 如果您不能使用它,我认为您正在查看大量不同数量参数的重载。
  • @Useless:我怎样才能在没有 decltype 的情况下实现那个元组 typedef?我知道我必须为旧编译器提供大量重载,但我想没有办法解决这个问题。
【解决方案2】:

终于找到了一种在 C++03 中使用偏特化的方法。需要针对不同数量的参数和 const/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 提到的方法更简洁,应该是首选。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-01
    • 2019-10-23
    • 2015-09-26
    • 2016-06-12
    • 1970-01-01
    • 2011-02-21
    相关资源
    最近更新 更多