如何在c ++

时间:2019-01-17 13:21:05

标签: c++

对于我正在开发的二进制协议库,我广泛使用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函数,因为类型从不多态使用。

(模式应该像装饰器一样。)

有什么想法吗?谢谢。

1 个答案:

答案 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");
            }
        }
    };