获取函数参数个数

4

我想知道在C++11中是否有一种方法可以获取函数的参数数量?

例如,对于函数foo,我希望argCount为3。

void foo(int a, int b, int c) {}

int main() {
  size_t argCount = MAGIC(foo);
}

这有什么好处呢? - πάντα ῥεῖ
1
@πάνταῥεῖ,我至少知道一个在重度元编程中应用它的例子。 - SergeyA
6
如果存在多个参数个数不同的重载,那么MAGIC应该返回什么? - Baum mit Augen
3
@BaummitAugen应该会返回一个错误。如果你试图在没有上下文的情况下获取重载函数的地址,同样会返回错误。但不要把这视为程序无法继续运行的障碍。 - SergeyA
3个回答

12

您可以使用可变参数函数模板来获取该信息。

#include <iostream>

template <typename R, typename ... Types> constexpr size_t getArgumentCount( R(*f)(Types ...))
{
   return sizeof...(Types);
}

//----------------------------------    
// Test it out with a few functions.
//----------------------------------    

void foo(int a, int b, int c)
{
}

int bar()
{
   return 0;
}

int baz(double)
{
   return 0;
}

int main()
{
    std::cout << getArgumentCount(foo) << std::endl;
    std::cout << getArgumentCount(bar) << std::endl;
    std::cout << getArgumentCount(baz) << std::endl;
    return 0;
}

输出:

3
0
1

请在http://ideone.com/oqF8E8中查看它的工作方式。

更新

Barry建议使用:

template <typename R, typename ... Types> 
constexpr std::integral_constant<unsigned, sizeof ...(Types)> getArgumentCount( R(*f)(Types ...))
{
   return std::integral_constant<unsigned, sizeof ...(Types)>{};
}

使用此方法,您可以通过以下方式获取参数的数量:

// Guaranteed to be evaluated at compile time
size_t count = decltype(getArgumentCount(foo))::value;
或者
// Most likely evaluated at compile time
size_t count = getArgumentCount(foo).value;

@SergeyA,感谢你的提醒。现在比你的回答更简化了 :) - R Sahu
非常正确!:) 不过我的代码没有调用函数,而你的代码有。你需要将你的代码改为constexpr,但这仍然不能保证它永远不会被调用——这就是为什么我更喜欢我的版本。不过,你的代码更简单。 - SergeyA
@RSahu 更倾向于返回 integral_constant 而不是 size_t(请参见Columbo在重复问题上的回答) - Barry
@Barry,我理解在dupe中使用integral_constant的目的是为了简化struct get_arity的实现。对于像我在这里展示的自由函数,这不会增加任何额外的价值。如果我漏掉了什么微妙的东西,请告诉我。 - R Sahu
@RSahu 从将答案编码到类型的角度来看,它增加了额外的价值。将一切保持在类型层面上只会使元编程更加容易。此外,您可以将其传递给另一个函数,并且可根据不同的参数数量进行重载。 - Barry
显示剩余5条评论

9

没问题,这可以很容易地完成:

#include <cstddef>
#include <iostream>

template <class R, class... ARGS>
struct function_ripper {
    static constexpr size_t n_args = sizeof...(ARGS);
};


template <class R, class... ARGS>
auto constexpr make_ripper(R (ARGS...) ) {
  return function_ripper<R, ARGS...>();
}

void foo(int, double, const char*);

void check_args() {
  constexpr size_t foo_args = decltype(make_ripper(foo))::n_args;

  std::cout << "Foo has  " << foo_args << " arguments.\n";
}

也许可以像这样做:https://gcc.godbolt.org/z/4NWT_N - Ayxan Haqverdili

0
这个在几个方面上都不太合理。
首先,这真的有什么好处吗?你可能正在寻找某种反射,但C++中目前还没有这种功能。
然而,这个不合理的主要原因是重载集合:
void f(int);
void f(int, int);
std::cout << MAGIC(f); // what should this print??

1
有一种方法可以做到这一点。 - SergeyA
你能够做到并不意味着它有意义,不过没错,你是正确的。 - Ven
4
在许多模板元编程应用中,这是非常合理的。 - SergeyA
2
当你甚至不知道使用情况是什么时,为什么要说它没有意义呢?这正是绑定基于堆栈的脚本语言本地调用所需的,你需要参数计数。 - paulm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接