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

如何在无宏情况下结合std::source_location与可变参数实现日志

解决std::source_location与可变参数日志结合的位置错误问题

你的问题核心在于std::source_location的默认参数位置放错了——你把它放在底层_log函数里,而_log是被log模板函数调用的,所以std::source_location::current()会捕获log函数内部的调用位置,而非原始的日志调用点。

不用宏的解决方案很直接:把std::source_location的默认参数直接放到可变参数的log模板函数中,让它在日志的调用位置求值,再传递给底层函数。

修改后的完整代码

#include <source_location>
#include <string>
#include <string_view>
#include <iostream>
#include <fmt/format.h>

// 底层日志实现,接收已格式化的字符串和source_location
bool _log(std::string strFormatedDebugMessage, const std::source_location loc);

// 可变参数模板的日志入口,将source_location默认参数放在这里
template<typename ...Args>
bool log(fmt::format_string<Args...> fmt, Args&&... args, 
         const std::source_location loc = std::source_location::current())
{
    // 正确转发参数并格式化(你之前的代码未处理args,此处修正)
    std::string formatted_msg = fmt::format(fmt, std::forward<Args>(args)...);
    return _log(std::move(formatted_msg), loc);
}

bool _log(std::string strFormatedDebugMessage, const std::source_location loc)
{
    // 现在会正确显示原始调用log的行号
    std::cout << "Called from Line " << loc.line() << std::endl;
    std::cout << "Log: " << strFormatedDebugMessage << std::endl;

    // 实际写入硬件的逻辑(失败时返回false)
    return true;
}

int main()
{
    bool bRes = log("Log with format {} {} value", "Some dummy", 1); // 捕获此行的行号
    bRes &= log("Log without format args"); // 捕获此行的行号
    std::cout << "Hello World" << bRes << std::endl;
}

关键说明

  • source_location的位置:必须将std::source_location loc = std::source_location::current()作为log函数的最后一个参数(C++20允许默认参数放在可变参数包之后)。这样默认参数的求值会发生在log的调用点(比如main里的两行log调用),而非内部调用_log的位置。
  • 参数转发与格式化:用std::forward<Args>(args)...完美转发参数,确保fmt格式化的正确性,同时保留参数的原有属性。
  • 类型安全:fmt::format_string<Args...>保证格式字符串和参数类型匹配,编译期就能检查错误,比宏实现的类型安全性更高。

这样修改后,loc.line()会正确显示main函数中调用log的行号,完全不需要宏就能实现需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 03:52:05