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

求助:完成C++函数名解析标准化的constexpr静态存储实现

解决方案:编译期生成静态存储的精简函数名

要实现constexpr编译期解析+模板静态存储的方案,核心是利用模板实例的唯一性,将每个函数的精简名编译期计算后存入对应模板实例的静态成员中,避免冗余的__PRETTY_FUNCTION__字符串进入二进制。

核心思路

  1. constexpr解析函数:将你已有的函数名清理逻辑改造成完全constexpr兼容的实现,确保编译期就能完成字符串处理。
  2. 模板静态存储:通过函数指针作为模板参数,让每个函数对应唯一的模板实例,其静态成员存储编译期计算好的精简函数名,保证全局仅存一份。

代码实现

1. constexpr精简函数名解析

先把你的解析逻辑适配成constexpr版本(以下是示例逻辑,可替换为你已有的成熟实现):

#include <string_view>

constexpr std::string_view clean_function_name(std::string_view raw_name) {
    // 跳过开头空白
    size_t start = raw_name.find_first_not_of(" \t");
    if (start == std::string_view::npos) return "";
    raw_name = raw_name.substr(start);

    // 截断参数列表部分
    size_t paren_pos = raw_name.find('(');
    if (paren_pos != std::string_view::npos) {
        raw_name = raw_name.substr(0, paren_pos);
    }

    // 移除返回值前缀(适配多数编译器格式)
    size_t last_space = raw_name.find_last_of(' ');
    if (last_space != std::string_view::npos) {
        raw_name = raw_name.substr(last_space + 1);
    }

    // 特殊处理lambda
    if (raw_name.find("lambda") != std::string_view::npos) {
        return "lambda";
    }

    // 适配MSVC的__FUNCSIG__格式(可选)
    size_t msvc_scope = raw_name.rfind("::");
    if (msvc_scope != std::string_view::npos && raw_name.substr(0, msvc_scope).find("__cdecl") != std::string_view::npos) {
        raw_name = raw_name.substr(msvc_scope + 2);
    }

    return raw_name;
}

2. 模板静态存储结构体

用函数指针作为模板参数,确保每个函数对应唯一的模板实例,静态成员存储编译期计算的精简名:

template<typename FuncType, FuncType FuncPtr>
struct StaticFunctionName {
    // 编译期调用解析函数,结果存入静态成员
    static constexpr std::string_view value = clean_function_name(__PRETTY_FUNCTION__);
};

3. 辅助宏简化调用

针对普通函数和成员函数分别定义宏,减少重复代码:

// 普通函数调用宏
#define GET_CLEAN_FUNC_NAME() \
    StaticFunctionName<decltype(&__func__), &__func__>::value

// 成员函数调用宏(需在成员函数内部使用)
#define GET_CLEAN_MEMBER_FUNC_NAME() \
    StaticFunctionName<decltype(&std::remove_reference_t<decltype(*this)>::__func__), \
                       &std::remove_reference_t<decltype(*this)>::__func__>::value

4. 测试示例

#include <iostream>

void plain_function() {
    constexpr auto name = GET_CLEAN_FUNC_NAME();
    std::cout << name << '\n'; // 输出: plain_function
}

class TestClass {
public:
    void member_function() {
        constexpr auto name = GET_CLEAN_MEMBER_FUNC_NAME();
        std::cout << name << '\n'; // 输出: member_function
    }
};

template<typename T>
void template_function(T) {
    constexpr auto name = GET_CLEAN_FUNC_NAME();
    std::cout << name << '\n'; // 输出: template_function
}

int main() {
    plain_function();
    TestClass{}.member_function();
    template_function(42);
    template_function("test");
    
    // Lambda测试
    auto lambda = []() {
        constexpr auto name = GET_CLEAN_FUNC_NAME();
        std::cout << name << '\n'; // 输出: lambda
    };
    lambda();
    
    return 0;
}

为什么能避免代码膨胀?

  • 编译期计算:clean_function_name在编译期完成所有字符串处理,__PRETTY_FUNCTION__的原始冗余字符串仅在编译阶段被读取,不会进入最终二进制。
  • 模板实例唯一性:每个函数(包括模板函数的不同实例、成员函数)对应唯一的StaticFunctionName模板实例,其静态成员value全局仅存储一份,不会重复生成冗余数据。

关键注意事项

  1. 编译器兼容性:不同编译器的__PRETTY_FUNCTION__/__FUNCSIG__格式不同,需在clean_function_name中适配(你的现有工具应该已经处理了这部分,只需迁移到constexpr逻辑)。
  2. C++版本要求:需使用C17及以上(支持std::string_view的constexpr成员函数),C20可获得更完善的字符串操作支持。
  3. 特殊函数处理:lambda、虚函数、重载函数的__func__/函数指针推导需单独适配,比如lambda的__func__是operator(),需在解析逻辑中识别替换。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 14:52:35