You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从模板化函数的函数指针中提取参数类型并分支调用?

提取函数指针参数类型并实现分支逻辑的方案

完全可以实现提取函数指针的参数类型,并在模板中根据参数类型做编译期分支处理,以下是针对单参数和可变参数场景的具体实现:

一、单参数函数指针的实现

首先定义类型萃取模板,用来提取函数指针的返回值、参数类型等信息:

#include <type_traits>
#include <iostream>

// 基础模板,用于匹配函数指针
template<typename F>
struct function_traits;

// 特化:匹配单参数函数指针
template<typename Ret, typename Arg>
struct function_traits<Ret(*)(Arg)> {
    using return_type = Ret;
    using first_arg_type = Arg;
    static constexpr size_t arg_count = 1;
};

// 原模板函数,根据参数类型分支处理
template <typename FncPtr>
void f(FncPtr fp)
{
    using traits = function_traits<FncPtr>;
    if constexpr (std::is_same_v<typename traits::first_arg_type, double>) {
        fp(1.0);
    }
    else if constexpr (std::is_same_v<typename traits::first_arg_type, int>) {
        fp(25);
    }
    else {
        // 编译期断言,提示不支持的参数类型
        static_assert(!std::is_same_v<FncPtr, FncPtr>, "Unsupported argument type for function pointer");
    }
}

// 测试用例
void print_double(double d) { std::cout << "Double value: " << d << "\n"; }
void print_int(int i) { std::cout << "Int value: " << i << "\n"; }

int main() {
    f(print_double); // 输出:Double value: 1.0
    f(print_int);    // 输出:Int value: 25
    // f(print_float); // 触发编译期错误:Unsupported argument type for function pointer
    return 0;
}

二、可变参数函数指针的实现

扩展类型萃取模板,支持提取可变参数列表中的任意位置参数类型,同时处理无参数的情况:

#include <type_traits>
#include <tuple>
#include <iostream>

// 基础模板
template<typename F>
struct function_traits;

// 特化:匹配可变参数函数指针
template<typename Ret, typename... Args>
struct function_traits<Ret(*)(Args...)> {
    using return_type = Ret;
    // 提取第N个参数类型(N从0开始)
    template<size_t N>
    using arg_type = std::tuple_element_t<N, std::tuple<Args...>>;
    static constexpr size_t arg_count = sizeof...(Args);
};

// 支持可变参数的模板函数
template <typename FncPtr>
void f(FncPtr fp)
{
    using traits = function_traits<FncPtr>;
    if constexpr (traits::arg_count == 0) {
        fp(); // 无参数时直接调用
    }
    else if constexpr (traits::arg_count >= 1) {
        using first_arg = typename traits::template arg_type<0>;
        if constexpr (std::is_same_v<first_arg, double>) {
            fp(1.0, "extra string"); // 传入符合函数签名的参数
        }
        else if constexpr (std::is_same_v<first_arg, int>) {
            fp(25, 3.14f, true);
        }
        else {
            static_assert(!std::is_same_v<FncPtr, FncPtr>, "Unsupported first argument type");
        }
    }
}

// 测试用例
void var_func_double(double d, const char* s) { std::cout << "Double: " << d << ", Str: " << s << "\n"; }
void var_func_int(int i, float f, bool b) { std::cout << "Int: " << i << ", Float: " << f << ", Bool: " << b << "\n"; }
void no_arg_func() { std::cout << "No arguments called\n"; }

int main() {
    f(var_func_double); // 输出:Double: 1, Str: extra string
    f(var_func_int);    // 输出:Int: 25, Float: 3.14, Bool: 1
    f(no_arg_func);     // 输出:No arguments called
    return 0;
}

注意事项

  • 上述代码依赖C++17及以上标准,因为使用了if constexpr实现编译期分支判断;
  • 类型萃取模板可以进一步扩展,支持std::function、成员函数指针、lambda等其他可调用对象;
  • 编译期断言static_assert用于在遇到不支持的参数类型时,直接在编译阶段报错,避免运行时问题。

内容的提问来源于stack exchange,提问作者SupAl

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 06:02:13