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

如何判断C++模板参数是函数、函数指针还是Lambda表达式?

区分函数、函数指针与Lambda并排除普通类的实现方案

要实现判断模板参数是函数、函数指针或Lambda,同时禁止普通类传入,可以通过模板元编程结合类型特征来完成,核心是利用Lambda闭包类型的标准特性(final类、包含operator())区分普通类与Lambda。

核心思路

  1. 函数类型判断:直接用std::is_function_v识别原始函数类型(注意函数作为参数传递时通常会退化为指针,仅显式指定模板参数时才会保留函数类型)。
  2. 函数指针判断:结合std::is_pointer_v和std::is_function_v<std::remove_pointer_t<T>>,判断指针指向的是函数类型。
  3. Lambda判断:Lambda的闭包类型是标准规定的final类,且必然包含operator()成员函数,因此通过std::is_class_v+std::is_final_v+自定义的has_call_operator_v来识别。
  4. 普通类排除:通过static_assert静态断言,仅允许上述三种类型通过编译,普通类会触发编译错误。

代码实现

#include <type_traits>
#include <iostream>
#include <utility>

namespace detail {
    // 辅助Trait:检查类型是否包含operator()
    template<typename T, typename = void>
    struct has_call_operator : std::false_type {};

    template<typename T>
    struct has_call_operator<T, std::void_t<decltype(&T::operator())>> : std::true_type {};

    template<typename T>
    inline constexpr bool has_call_operator_v = has_call_operator<T>::value;
}

// 判断是否为Lambda表达式
template<typename T>
inline constexpr bool is_lambda_v = 
    std::is_class_v<T> && 
    std::is_final_v<T> && 
    detail::has_call_operator_v<T>;

// 判断是否为函数指针
template<typename T>
inline constexpr bool is_function_pointer_v = 
    std::is_pointer_v<T> && 
    std::is_function_v<std::remove_pointer_t<T>>;

// 判断是否为函数类型
template<typename T>
inline constexpr bool is_function_v = std::is_function_v<T>;

// 处理可调用对象的模板函数
template<typename Callable>
void process_callable(Callable&& c) {
    // 静态断言:仅允许函数、函数指针、Lambda传入
    static_assert(
        is_function_v<std::decay_t<Callable>> || 
        is_function_pointer_v<std::decay_t<Callable>> || 
        is_lambda_v<std::decay_t<Callable>>,
        "Callable must be a function, function pointer, or lambda expression"
    );

    // 编译时分支处理不同类型
    if constexpr (is_function_v<std::decay_t<Callable>>) {
        std::cout << "This is a function type\n";
    } else if constexpr (is_function_pointer_v<std::decay_t<Callable>>) {
        std::cout << "This is a function pointer\n";
    } else if constexpr (is_lambda_v<std::decay_t<Callable>>) {
        std::cout << "This is a lambda expression\n";
    }
}

// 测试用例
void foo() {}

// 普通用户类(会触发静态断言错误)
struct MyClass {
    void operator()() {}
};

int main() {
    process_callable(foo);          // 输出:This is a function pointer(函数退化为指针)
    process_callable(&foo);         // 输出:This is a function pointer
    process_callable([](){});       // 输出:This is a lambda expression
    // process_callable(MyClass{}); // 取消注释会触发编译错误:符合需求
    return 0;
}

关键细节说明

  • std::decay_t:用于处理传入参数的引用、cv限定符,确保我们检查的是原始类型。
  • std::is_final_v:Lambda的闭包类型是标准规定的final类,普通用户类默认不是final(除非显式声明),这是区分Lambda与普通类的核心依据。
  • C++版本兼容:代码使用了C17的constexpr if,若需兼容C14及以下,可改用模板特化替代编译时分支。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 20:24:58