保持函数参数的保守性
Keeping consteval-ness of function arguments
我正在使用 neat fmt 库,如果编译器支持相关功能,它的版本 8 会在编译时检查其格式字符串。
在某些时候,我想编写以下代码:
throw my_exception("error: {}", 123);
可悲的是,天真的实现:
struct my_exception : std::runtime_error {
template<typename... Args>
my_exception(Args&&... args)
: std::runtime_error{fmt::format(std::forward<Args>(args)...)}
{ }
};
失败,因为这失去了 fmt::format
所要求的字符串文字参数的“consteval-ness”。
现在,我确定了以下几点:
template<std::size_t N>
struct literal {
constexpr literal(const char (&str)[N]) noexcept {
std::copy_n(str, N, this->str);
}
char str[N];
};
template<literal lit>
struct exception : std::runtime_error {
template<typename... Args>
exception(Args&&... args)
: std::runtime_error{fmt::format(lit.str, std::forward<Args>(args)...)}
{
}
};
被称为
throw my_exception<"foo {}">(123);
如何恢复正常的函数调用语法,同时保持编译时检查?
在 {fmt} 8.0 及更高版本中,您可以使用 format_string
模板来执行此操作,顾名思义,该模板表示格式字符串 (https://godbolt.org/z/bqvvMMnjG):
struct my_exception : std::runtime_error {
template <typename... T>
my_exception(fmt::format_string<T...> fmt, T&&... args)
: std::runtime_error(fmt::format(fmt, std::forward<T>(args)...)) {}
};
我正在使用 neat fmt 库,如果编译器支持相关功能,它的版本 8 会在编译时检查其格式字符串。
在某些时候,我想编写以下代码:
throw my_exception("error: {}", 123);
可悲的是,天真的实现:
struct my_exception : std::runtime_error {
template<typename... Args>
my_exception(Args&&... args)
: std::runtime_error{fmt::format(std::forward<Args>(args)...)}
{ }
};
失败,因为这失去了 fmt::format
所要求的字符串文字参数的“consteval-ness”。
现在,我确定了以下几点:
template<std::size_t N>
struct literal {
constexpr literal(const char (&str)[N]) noexcept {
std::copy_n(str, N, this->str);
}
char str[N];
};
template<literal lit>
struct exception : std::runtime_error {
template<typename... Args>
exception(Args&&... args)
: std::runtime_error{fmt::format(lit.str, std::forward<Args>(args)...)}
{
}
};
被称为
throw my_exception<"foo {}">(123);
如何恢复正常的函数调用语法,同时保持编译时检查?
在 {fmt} 8.0 及更高版本中,您可以使用 format_string
模板来执行此操作,顾名思义,该模板表示格式字符串 (https://godbolt.org/z/bqvvMMnjG):
struct my_exception : std::runtime_error {
template <typename... T>
my_exception(fmt::format_string<T...> fmt, T&&... args)
: std::runtime_error(fmt::format(fmt, std::forward<T>(args)...)) {}
};