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

如何在编译时处理std::source_location::function_name()并生成可运行时使用的字符串(避免硬编码大小与固定字符串)

如何在编译时处理std::source_location::function_name()并生成可运行时使用的字符串(避免硬编码大小与固定字符串)

当然可以做到!你的核心需求是在编译时处理std::source_location::function_name()的结果(比如每个字符重复一次),同时避免硬编码字符串长度和固定测试字符串——利用C++20的consteval、模板参数推导以及std::source_location的constexpr特性,完全可以解决这两个TODO问题,而且全程在编译时完成处理,运行时零开销。

针对你的场景(MSVC 17.10,该版本对C++20相关特性支持完善),我整理了修正后的完整代码,并逐部分解释思路:

#include <array>
#include <iostream>
#include <source_location>
#include <string>

// 编译时处理函数名:将每个字符重复一次,末尾加结束符
consteval auto process_function_name(const std::source_location loc) {
    // 编译时获取函数名字符串及其长度
    const char* name = loc.function_name();
    size_t name_len = 0;
    while (name[name_len] != '\0') ++name_len;

    // 计算处理后的字符串长度:原长度*2 + 1(结束符)
    constexpr size_t calc_output_len(size_t input_len) {
        return input_len * 2 + 1;
    }
    std::array<char, calc_output_len(name_len)> processed{};

    // 编译时填充处理后的字符串
    size_t output_idx = 0;
    for (size_t i = 0; i < name_len; ++i) {
        processed[output_idx++] = name[i];
        processed[output_idx++] = name[i];
    }
    processed[output_idx] = '\0'; // 确保字符串以结束符结尾
    return processed;
}

// 模板化的结构体,自动推导处理后的字符串长度
template<size_t ProcessedLen>
struct StringWithSourceLocation {
    const char* message;
    std::source_location source_loc;
    std::array<char, ProcessedLen> processed_func_name;

    // 构造函数:自动推导处理后的字符串长度,获取调用点的source_location
    template<size_t L = process_function_name(std::source_location::current()).size()>
    consteval StringWithSourceLocation(const char* msg, std::source_location loc = std::source_location::current())
        : message(msg), source_loc(loc), processed_func_name(process_function_name(loc)) {}
};

// 日志函数:自动推导模板参数
template<size_t ProcessedLen>
void log(const StringWithSourceLocation<ProcessedLen>& log_data) {
    std::cout << log_data.processed_func_name.data() << ": " << log_data.message << std::endl;
}

int main() {
    log("bar");
}

关键改进点说明

  1. 彻底去掉硬编码的字符串和长度

    • 我们直接在consteval函数process_function_name中使用传入的std::source_location对象的function_name()方法——因为std::source_location是constexpr类型,它的成员函数在consteval上下文(编译时执行)中完全可用,不需要硬编码测试字符串。
    • 函数名的长度也是在编译时通过遍历字符串计算的,不需要提前硬编码N。
  2. 自动推导处理后的字符串长度

    • StringWithSourceLocation被改为模板类,模板参数ProcessedLen就是处理后的字符串数组长度。
    • 构造函数通过模板参数推导(template<size_t L = ...>)自动获取process_function_name返回的数组大小,完全不需要手动指定长度。
  3. 编译时完成所有处理

    • 所有字符串处理逻辑都在consteval函数中执行,这意味着整个字符重复、数组生成的过程都在编译阶段完成,运行时只是直接读取预先生成的数组,没有任何额外开销。

运行效果

当你在MSVC 17.10中编译运行这段代码时,会输出类似以下内容(具体函数名字符串格式取决于MSVC的实现):

iInntt  __ccddeeccll  mmaaiinn((vvooiidd)): bar

扩展提示

如果需要更复杂的编译时函数名处理(比如提取纯函数名、去掉命名空间或参数列表),只需要在process_function_name中添加对应的编译时逻辑即可——比如遍历字符串找到(的位置,截断到该位置之前的内容,或者跳过命名空间前缀等,所有操作都可以在consteval上下文里完成。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 07:58:04