C++20下fmt::format_string编译失败:原因及修复方案
C++20下fmt格式字符串编译失败的原因与修复方案
问题背景
以下代码在--std=c++17编译时正常运行,但切换到--std=c++20后编译失败:
#include <fmt/core.h> template <typename ...T> void func( const fmt::format_string<T...>& str, T&& ...args ) { auto _ = fmt::format( str, args... ); } int main() { func( "foo {}", 3 ); }
编译报错信息:
consteval fmt::v10::basic_format_string<Char, Args>::basic_format_string(const S&) ... (with S= and a bunch of akas) ... in constant expression
一、C++20导致问题的核心原因
fmt v10.0.0针对C20做了优化:fmt::format_string的构造函数被标记为consteval。这个C20新关键字要求函数必须在编译期常量表达式中执行,不能推迟到运行时。
在C17中,该构造函数是普通的运行时构造,字符串字面量可以正常绑定到const fmt::format_string<T...>&参数。但C20下,编译器需要在编译期完成format_string对象的构造,而模板函数存在推导时序冲突:编译器需要先推导T...的类型才能确定format_string的模板参数,但format_string的consteval构造又要求在推导完成前就完成常量表达式求值,两者矛盾导致编译失败。
二、兼容C++20的代码修改方案
有两种简洁的修复方式:
方案1:将format_string改为值传递(推荐)
把第一个参数的const &去掉,改为值传递,这样编译器可以先在常量表达式中构造format_string对象,再完成模板参数推导,完全符合consteval的要求:
#include <fmt/core.h> #include <utility> // 用于std::forward template <typename ...T> void func( fmt::format_string<T...> str, T&& ...args ) { auto _ = fmt::format( str, std::forward<T>(args)... ); } int main() { func( "foo {}", 3 ); }
方案2:显式指定模板参数
如果坚持使用引用传递,可以显式告诉编译器T...的类型,避免推导冲突,但这种方式不够灵活:
int main() { func<int>( "foo {}", 3 ); // 显式指定模板参数为int }
内容的提问来源于stack exchange,提问作者R K
相关产品推荐
相关产品推荐

