为什么将字符串文字传递给调用 std::format 的模板无法编译?
Why passing a string literal to a template calling std::format fails to compile?
以下代码片段无法在最新版本的 MSVC (Visual Studio 2022 17.2.2) 上编译。相同的片段似乎在以前的编译器版本上工作得很好。
#include <iostream>
#include <format>
template <typename First, typename... Args>
inline auto format1(First&& first, Args&&... args) -> decltype(std::format(first, std::forward<Args>(args)...))
{
return std::format(std::forward<First>(first), std::forward<Args>(args)...);
}
int main()
{
std::cout << format1("hi {} {}", 123, 456);
}
编译器发出以下错误:
1>ConsoleApplication3.cpp(10,24): message : failure was caused by a
read of a variable outside its lifetime
1>ConsoleApplication3.cpp(10,24): message : see usage of 'first'
1>ConsoleApplication3.cpp(14): message : see reference to function
template instantiation 'std::string format<const
char(&)[9],int,int>(First,int &&,int &&)' being compiled 1>
with 1> [ 1> First=const char (&)[9] 1> ]
似乎以某种方式将字符串文字转发到 std::format 会使编译器认为它们在其生命周期之外使用。我尝试更改函数以接受 const First& first
和各种其他变体,但错误仍然存在。
据我了解,当First
被推导为const引用时,它的生命周期应该延长到被调用函数的范围内。
那么为什么会出现此错误?我该如何解决这个问题?
进一步调查,这似乎是 std::format.
的使用所特有的东西
此代码段在提供字符串文字时工作正常:
template <std::size_t COUNT>
inline auto format2(const char (&first)[COUNT])
{
std::cout << first;
}
而这个没有:
template <std::size_t COUNT>
inline auto format2(const char (&first)[COUNT])
{
std::format(first);
}
在P2216之后,std::format
要求格式化字符串必须是核心常量表达式。在您的情况下,编译失败是因为函数参数 First
不是常量表达式。
解决方法是使用 std::vformat
,它适用于运行时格式字符串
template<typename First, typename... Args>
auto format1(First&& first, Args&&... args) {
return std::vformat(
std::forward<First>(first),
std::make_format_args(std::forward<Args>(args)...));
}
如果你真的想使用std::format
,你可以传入一个lambda,returns一个字符串
template<typename First, typename... Args>
auto format1(First first, Args&&... args) {
return std::format(first(), std::forward<Args>(args)...);
}
int main() {
std::cout << format1([]{ return "hi {} {}"; }, 123, 456);
}
以下代码片段无法在最新版本的 MSVC (Visual Studio 2022 17.2.2) 上编译。相同的片段似乎在以前的编译器版本上工作得很好。
#include <iostream>
#include <format>
template <typename First, typename... Args>
inline auto format1(First&& first, Args&&... args) -> decltype(std::format(first, std::forward<Args>(args)...))
{
return std::format(std::forward<First>(first), std::forward<Args>(args)...);
}
int main()
{
std::cout << format1("hi {} {}", 123, 456);
}
编译器发出以下错误:
1>ConsoleApplication3.cpp(10,24): message : failure was caused by a read of a variable outside its lifetime 1>ConsoleApplication3.cpp(10,24): message : see usage of 'first' 1>ConsoleApplication3.cpp(14): message : see reference to function template instantiation 'std::string format<const char(&)[9],int,int>(First,int &&,int &&)' being compiled 1>
with 1> [ 1> First=const char (&)[9] 1> ]
似乎以某种方式将字符串文字转发到 std::format 会使编译器认为它们在其生命周期之外使用。我尝试更改函数以接受 const First& first
和各种其他变体,但错误仍然存在。
据我了解,当First
被推导为const引用时,它的生命周期应该延长到被调用函数的范围内。
那么为什么会出现此错误?我该如何解决这个问题?
进一步调查,这似乎是 std::format.
的使用所特有的东西此代码段在提供字符串文字时工作正常:
template <std::size_t COUNT>
inline auto format2(const char (&first)[COUNT])
{
std::cout << first;
}
而这个没有:
template <std::size_t COUNT>
inline auto format2(const char (&first)[COUNT])
{
std::format(first);
}
在P2216之后,std::format
要求格式化字符串必须是核心常量表达式。在您的情况下,编译失败是因为函数参数 First
不是常量表达式。
解决方法是使用 std::vformat
,它适用于运行时格式字符串
template<typename First, typename... Args>
auto format1(First&& first, Args&&... args) {
return std::vformat(
std::forward<First>(first),
std::make_format_args(std::forward<Args>(args)...));
}
如果你真的想使用std::format
,你可以传入一个lambda,returns一个字符串
template<typename First, typename... Args>
auto format1(First first, Args&&... args) {
return std::format(first(), std::forward<Args>(args)...);
}
int main() {
std::cout << format1([]{ return "hi {} {}"; }, 123, 456);
}