对于我正在开发的二进制协议库,我广泛使用StrongType<T>
,并将这一概念扩展到Enums。
我有一个InBitStream
对象,它实现了逐位读取字节数组的功能,我的意思是,每个字段都可以以固定和预定义的位数从数组中读取。
例如,我可以读取存储在5位中的StrongType
d字段,然后以这种方式读取另外3位:
class SomePacketType {
void readFromStream(DataPacket const &p) {
InBitStream stream(p);
auto field1 = makeBitField<5>(mFirstField); // references to mFirstField, using 5 bits
auto field2 = makeBitField<3>(mSecondField); // same, 3 bits
stream >> field1 >> field2;
}
当然,在某处定义了此运算符
class InBitStream {
template<int N, typename T, typename TAG>
friend InBitStream &operator >> (InBitStream &stream, BitField<N,StrongType<T,TAG>> &value) { ...
}
}
对枚举也是如此。枚举是这样定义的:
struct XTag {
};
enum class XEnum {
N = 0, A = 1, B = 2, C = 3, D = 4,
};
using X = utils::BitAwareEnum<3, XEnum, XTag>;
我现在的想法是添加一个验证函数,以检查是否从流中读取了一个枚举(或强类型)并根据某些特殊值进行了验证。例如X
不应接收> 4的值。
我的目的是通过这种方式使用它,假设有一个ValidatedField
概念:
template <???>
InStream &operator >> (InStream &stream, ValidatedField<???> &v) {
v.validate();
return stream >> static_cast<some_base_class?>(v);
}
应如何定义ValidatedField? 请注意,验证功能取决于模板类型。例如,对于StrongType,它会检查它是否为正,而对于枚举,它必须检查max,min和一些内部无效值。
要求ValidatedField具有与类型相同的接口,所以我不能编写它,并且不允许virtual
函数,因为类型从不多态使用。
(模式应该像装饰器一样。)
有什么想法吗?谢谢。
答案 0 :(得分:1)
那时我能够找到一个好的解决方案。
这是ValidatedField
类。
template<typename Type, typename Validator>
struct ValidatedType : Type {
friend InBitStream &operator>>(InBitStream &stream, ValidatedType<Type, Validator> &v)
{
stream >> static_cast<Type &>(v);
Validator::validate(v);
return stream;
}
};
这只是为Validated类型创建一个Tag。流运算符>>
是使用它调度的。 Type
模板类型用于公开嵌入式类型,而Validator
类型则与functor
相似。验证程序必须公开静态函数validate(Type &const)
。
在流运算符实现中,v
参数必须转换为Type &
,以正确地对“装饰”类型调用相同的操作。
这是它的用法:
struct XTag {
};
enum class XEnum {
A = 1, B = 2, C = 3, D = 4,
};
using XE = utils::BitAwareEnum<4, XEnum, XTag>;
struct XValidator {
static void validate(XE const &x)
{
if (x.underlyingValue() <= 0 || x.underlyingValue() > 4) {
throw utils::InBitStream::IllegalValueException("Illegal XE value");
}
}
};
using X = utils::ValidatedType<XE, XValidator>;
X x;
我喜欢这个解决方案: -我有一棵装饰类型的“树”,其功能可以根据需要“插入”
我不喜欢这种解决方案:
-XValidator
的结构有些冗长,我希望采用一种更具可读性的方式来实现它。我需要记住,validate()
函数必须声明为静态。
请随时评论改进或替代解决方案。
对于那些好奇的人来说,该项目在以下位置开源:https://gitlab.com/ffuga/gutils
更新:
诚如@Incomputable所指出,这是Policy Based design。
按照Wikipedia页面中的示例重新排列代码,我修复了“静态”问题。
这是非常确定的代码:
template<typename Type, typename Validator>
struct ValidatedType : Type, Validator {
using Validator::validate;
friend InBitStream &operator>>(InBitStream &stream, ValidatedType<Type, Validator> &v)
{
stream >> static_cast<Type &>(v);
v.validate(v);
return stream;
}
};
用法:
struct XValidator {
void validate(XE const &x)
{
if (x.underlyingValue() <= 0 || x.underlyingValue() > 4) {
throw utils::InBitStream::IllegalValueException("Illegal XE value");
}
}
};