我正在尝试使用 {fmt} 格式化模板
I'm trying to format a template using {fmt}
我有一个简单的模板,有点像:
template <typename T, T Min, T Max>
class LimitedInt {
public:
static_assert(Min < Max, "Min must be less than Max");
explicit LimitedInt(const T value)
{
setValue(value);
}
void setValue(const T value)
{
if (value < Min || value > Max) {
throw std::invalid_argument("invalid value");
}
mValue = value;
}
T getValue() const
{
return mValue;
}
private:
T mValue{Min};
}
这让我可以将其专门化为:
using Vlan = LimitedInt<uint16_t, 0, 4094>;
我希望能够使用
之类的格式来格式化值
Vlan v{42};
fmt::format("{:04x}", v);
为此,我试图将格式化职责转发给 formatter<int>
作为 但一无所获。我的尝试看起来像:
namespace fmt {
template <>
struct formatter<LimitedInt> {
formatter<int> int_formatter;
template <typename ParseContext>
constexpr auto parse(ParseContext& ctx)
{
return int_formatter.parse(ctx);
}
template <typename FormatContext>
auto format(const LimtedInt& li, FormatContext& ctx)
{
return int_formatter.format(li.getValue(), ctx);
}
};
} // namespace fmt
我已经尝试了几种变体,但都没有成功,错误往往围绕着这个:
In file included from /output/build/proj-local/src/networkinterface.h:8:0,
from /output/build/proj-local/src/networkinterface.cpp:3:
/output/build/proj-local/src/limitedints.h:78:38: error: type/value mismatch at argument 1 in template parameter list for 'template<class T, class Char, class Enable> struct fmt::v7::formatter'
struct formatter<LimitedInt> {
^
/output/build/proj-local/src/limitedints.h:78:38: note: expected a type, got 'LimitedInt'
我目前的解决方法是拥有一个成熟的格式化程序,它有自己的 parse()
和 format()
方法,但对我来说重新发明 Victor 已经写过的轮子充其量是愚蠢的。
通常的专业化规则适用。具体来说,您应该使 formatter
成为模板并将模板参数传递给 LimitedInt
:
template <typename T, T Min, T Max>
struct fmt::formatter<LimitedInt<T, Min, Max>> {
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
auto format(const LimitedInt<T, Min, Max>& val, format_context& ctx) {
// Format val and write the output to ctx.out().
return ctx.out();
}
};
我最后得到的是:
namespace fmt {
template <typename T, T Min, T Max>
struct formatter<LimitedInt<T, Min, Max>> {
formatter<int> int_formatter;
constexpr auto parse(format_parse_context& ctx)
{
return int_formatter.parse(ctx);
}
auto format(const LimitedInt<T, Min, Max>& li, format_context& ctx)
{
return int_formatter.format(li.getValue(), ctx);
}
};
} // namespace fmt
它通过了我所有的单元测试。在此过程中,我了解了更多有关 C++ 模板的知识。感谢 Werner、Igor 和 Victor,他们都帮助我指明了正确的方向。从 C 到 C++ 的过渡并不总是一帆风顺的。
我有一个简单的模板,有点像:
template <typename T, T Min, T Max>
class LimitedInt {
public:
static_assert(Min < Max, "Min must be less than Max");
explicit LimitedInt(const T value)
{
setValue(value);
}
void setValue(const T value)
{
if (value < Min || value > Max) {
throw std::invalid_argument("invalid value");
}
mValue = value;
}
T getValue() const
{
return mValue;
}
private:
T mValue{Min};
}
这让我可以将其专门化为:
using Vlan = LimitedInt<uint16_t, 0, 4094>;
我希望能够使用
之类的格式来格式化值Vlan v{42};
fmt::format("{:04x}", v);
为此,我试图将格式化职责转发给 formatter<int>
作为
namespace fmt {
template <>
struct formatter<LimitedInt> {
formatter<int> int_formatter;
template <typename ParseContext>
constexpr auto parse(ParseContext& ctx)
{
return int_formatter.parse(ctx);
}
template <typename FormatContext>
auto format(const LimtedInt& li, FormatContext& ctx)
{
return int_formatter.format(li.getValue(), ctx);
}
};
} // namespace fmt
我已经尝试了几种变体,但都没有成功,错误往往围绕着这个:
In file included from /output/build/proj-local/src/networkinterface.h:8:0,
from /output/build/proj-local/src/networkinterface.cpp:3:
/output/build/proj-local/src/limitedints.h:78:38: error: type/value mismatch at argument 1 in template parameter list for 'template<class T, class Char, class Enable> struct fmt::v7::formatter'
struct formatter<LimitedInt> {
^
/output/build/proj-local/src/limitedints.h:78:38: note: expected a type, got 'LimitedInt'
我目前的解决方法是拥有一个成熟的格式化程序,它有自己的 parse()
和 format()
方法,但对我来说重新发明 Victor 已经写过的轮子充其量是愚蠢的。
通常的专业化规则适用。具体来说,您应该使 formatter
成为模板并将模板参数传递给 LimitedInt
:
template <typename T, T Min, T Max>
struct fmt::formatter<LimitedInt<T, Min, Max>> {
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
auto format(const LimitedInt<T, Min, Max>& val, format_context& ctx) {
// Format val and write the output to ctx.out().
return ctx.out();
}
};
我最后得到的是:
namespace fmt {
template <typename T, T Min, T Max>
struct formatter<LimitedInt<T, Min, Max>> {
formatter<int> int_formatter;
constexpr auto parse(format_parse_context& ctx)
{
return int_formatter.parse(ctx);
}
auto format(const LimitedInt<T, Min, Max>& li, format_context& ctx)
{
return int_formatter.format(li.getValue(), ctx);
}
};
} // namespace fmt
它通过了我所有的单元测试。在此过程中,我了解了更多有关 C++ 模板的知识。感谢 Werner、Igor 和 Victor,他们都帮助我指明了正确的方向。从 C 到 C++ 的过渡并不总是一帆风顺的。