问题描述
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,4094>;
我希望能够用类似的东西格式化值
Vlan v{42};
fmt::format("{:04x}",v);
为此,我尝试将格式化职责作为 described here 转发给 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,Max>& val,format_context& ctx) {
// Format val and write the output to ctx.out().
return ctx.out();
}
};
Godbolt:https://godbolt.org/z/Mnjsbc
,我最终得到的是:
namespace fmt {
template <typename T,T Max>
struct formatter<LimitedInt<T,Max>> {
formatter<int> int_formatter;
constexpr auto parse(format_parse_context& ctx)
{
return int_formatter.parse(ctx);
}
auto format(const LimitedInt<T,Max>& li,format_context& ctx)
{
return int_formatter.format(li.getValue(),ctx);
}
};
} // namespace fmt
它通过了我所有的单元测试。一路上,我学到了更多关于 C++ 模板的知识。感谢 Werner、Igor 和 Victor,他们都帮助我指明了正确的方向。从 C 到 C++ 的过渡并不总是一帆风顺的。