C++中如何向使用std::format的嵌套lambda传递捕获参数避免报错?
为什么按值捕获的Lambda中使用std::format报错,printf却正常?
问题原因
std::format的第一个格式字符串参数要求是编译期常量表达式,这是为了在编译阶段就完成格式字符串与参数的匹配检查,避免运行时错误。而你的Lambda中按值捕获的fmt是存储在Lambda闭包中的运行时变量,不属于常量表达式范畴,因此无法满足std::format的参数要求,触发编译错误。
反观printf作为C风格函数,对格式字符串没有编译期常量的强制约束,它仅在运行时解析格式字符串,所以即使传递的是运行时变量也能正常编译运行。
解决方案
根据使用场景,有两种可行的解决方式:
1. 格式字符串为编译期固定值时:将格式字符串作为模板参数传递
如果格式字符串是编译期已知的固定值,可以把它设为模板参数,这样既能满足std::format对常量表达式的要求,还能享受编译期格式检查的优势:
#include <cstdio> #include <format> #include <iostream> template<typename F> void do_something_with_lambda(F&& lambda) { lambda(); } template<std::string_view fmt_str, typename ...Args> void func(Args&&... args) { do_something_with_lambda([...args = std::forward<Args>(args)]() { std::cout << std::format(fmt_str, args...); }); } template<typename ...Args> void func2(char const* fmt, Args&&... args) { do_something_with_lambda([fmt = fmt, ...args = args]() { printf(fmt, args...); }); } int main() { func<"hello {}">(12); // 格式字符串作为模板参数传入 func2("hello %d", 12); }
2. 格式字符串为运行时动态值时:使用std::vformat
如果格式字符串需要在运行时动态生成,可以用std::vformat代替std::format。std::vformat接受运行时的格式字符串,配合std::make_format_args打包参数列表即可:
#include <cstdio> #include <format> #include <iostream> #include <utility> template<typename F> void do_something_with_lambda(F&& lambda) { lambda(); } template<typename ...Args> void func(char const* fmt, Args&&... args) { do_something_with_lambda([fmt = fmt, ...args = std::forward<Args>(args)]() { // 使用std::vformat处理运行时格式字符串 std::cout << std::vformat(fmt, std::make_format_args(args...)); }); } template<typename ...Args> void func2(char const* fmt, Args&&... args) { do_something_with_lambda([fmt = fmt, ...args = args]() { printf(fmt, args...); }); } int main() { func("hello {}", 12); func2("hello %d", 12); }
内容的提问来源于stack exchange,提问作者user5406764
相关产品推荐
相关产品推荐

