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

C++17升级C++20后const char*不再是常量表达式的问题

C++20升级后spdlog日志封装编译错误分析与解决

问题背景

项目基于spdlog封装日志功能,在C17环境下编译运行正常。升级至C20后,调用vtek_log_error("Error, wrong parameter: {}", myParam);这类代码时触发编译错误,提示message不是常量表达式。

封装头文件代码

#pragma once

#include <memory>
#include <string>
#include <spdlog/spdlog.h>

namespace vtek
{
    void initialize_logging(const InitInfo* info);
    void terminate_logging();
    void disable_logging();

    void flush_vtek_logger();
    void flush_client_logger();

    class LogContainer
    {
    public:
        static inline std::shared_ptr<spdlog::logger> sVtekLogger = nullptr;
        static inline std::shared_ptr<spdlog::logger> sClientLogger = nullptr;
    };
}

template<typename... Args>
inline void vtek_log_error(const char* message, const Args &... args)
{
    vtek::LogContainer::sVtekLogger->error(message, args...);
}

编译报错信息

in ‘constexpr’ expansion of ‘fmt::v9::basic_format_string<char, const std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, const long unsigned int&>(message)’
/<path>/vtek_logging.h:97:47: error: ‘message’ is not a constant expression
   97 |         vtek::LogContainer::sVtekLogger->error(message, args...);

原因分析

问题根源在于spdlog依赖的fmt库对C++20的适配逻辑:

  • C++20版本的fmt库(spdlog通常捆绑内置fmt)要求格式化字符串必须是编译期常量表达式,以此在编译阶段校验格式字符串与参数的匹配性,提升代码安全性与运行性能。
  • 你传入的是字符串字面量,但vtek_log_error函数中message是普通const char*参数——即便传入字面量,函数参数本身不属于常量表达式范畴,无法满足fmt库中basic_format_string的constexpr构造要求。

解决方案

修改封装函数的模板定义,将格式化字符串作为模板参数传入,让编译器将其识别为编译期常量:

#include <spdlog/fmt/ostr.h> // 确保引入必要的fmt头文件

template <fmt::format_string<Args...> Message, typename... Args>
inline void vtek_log_error(Message&& message, Args&&... args)
{
    vtek::LogContainer::sVtekLogger->error(std::forward<Message>(message), std::forward<Args>(args)...);
}

也可利用spdlog提供的类型别名简化写法:

template <spdlog::format_string_t<Args...> Message, typename... Args>
inline void vtek_log_error(Message&& message, Args&&... args)
{
    vtek::LogContainer::sVtekLogger->error(std::forward<Message>(message), std::forward<Args>(args)...);
}

修改后,传入字符串字面量时编译器会将其作为模板参数实例化,既满足fmt对常量表达式的要求,又保留了编译期格式检查的能力。

补充说明

这是spdlog/fmt库适配C20时的常见兼容性问题,并非编译器或代码逻辑的原生错误,核心是C20对constexpr能力的扩展,以及fmt库对编译期检查的强化。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 19:40:20