c++中如何获取函数参数的个数_c++模板元编程获取参数数量【汇总】

无法直接用std::tuple_size配合std::function获取参数个数,因argument_type仅对0/1参函数定义;正确方法是依赖函数类型+可变模板偏特化实现arity元函数,或C++17起结合std::invoke_result辅助推导。

c++中如何获取函数参数的个数_c++模板元编程获取参数数量【汇总】

std::tuple_size 配合 std::function 无法直接获取函数参数个数

很多人第一反应是把函数转成 std::function,再用 std::tuple_size,但这是错的:std::functionargument_type 只对无参或单参函数有定义,多参时根本不存在这个类型别名,编译直接失败。

真正可行的路只有一条:依赖函数类型本身 + 模板参数推导。核心思路是写一个能匹配任意函数签名的可变参数模板,让编译器帮我们“数”参数。

用可变参数模板偏特化提取参数包长度

最稳定、兼容 C++11 起的方法是定义一个元函数 arity,通过函数指针类型或 lambda 类型的模板参数展开来计数:

template
struct arity;

template
struct arity {
    static constexpr size_t value = sizeof...(Args);
};

template
struct arity {
    static constexpr size_t value = sizeof...(Args);
};

template
struct arity {
    static constexpr size_t value = sizeof...(Args);
};

template
struct arity {
    static constexpr size_t value = sizeof...(Args);
};

使用时注意:

立即学习C++免费学习笔记(深入)”;

  • arity::value 对普通函数有效
  • 成员函数需加 &C::member_func,并确保 const 修饰符匹配
  • lambda 表达式不能直接用 decltype(lambda) —— 它是未命名闭包类型,不匹配上面任一偏特化;必须先转成函数指针(仅限无捕获)或用 std::function 包装后再提取,但后者又绕回了前面的问题

std::invoke_result 和参数占位推导(C++17+ 更简洁)

C++17 引入 std::invoke_result,虽然它本身不提供参数个数,但可以和辅助模板组合实现更泛化的提取:

Otter.ai

Otter.ai

一个自动的会议记录和笔记工具,会议内容生成和实时转录

下载

template
struct arity_v : std::integral_constant {};

template
struct arity_v> 
    : arity {};

// 然后仍需依赖上面的 arity 特化,只是自动适配了 lambda 和 functor

不过实际中,多数场景下你已知函数类型,直接写 sizeof...(Args) 更轻量。比如封装一个回调注册器时:

template
auto register_callback(Func&& f) {
    constexpr size_t N = arity>::value;
    static_assert(N <= 4, "Too many arguments (max 4 supported)");
    // ...
}

这种硬编码限制比运行时检查更早暴露问题。

容易被忽略的坑:重载函数、模板函数、函数对象

所有上述方法都要求传入的是**具体、可确定的类型**:

  • 对重载函数名(如 std::sin)直接取地址会报错:ambiguous overload
  • 模板函数(如 std::make_pair)必须显式指定模板参数才能取地址:&std::make_pair
  • 带捕获的 lambda 根本没有可转换的函数指针类型,sizeof... 无从下手;只能靠运行时包装(如用 std::any 存参数列表)或放弃静态计数

如果你真需要统一处理这三类,那就不是纯元编程能解决的了——得靠宏生成特化,或者接受运行时反射(目前标准 C++ 还不支持)。

https://www.php.cn/faq/2005201.html

发表回复

Your email address will not be published. Required fields are marked *