c++ - 如何在 C++ 中正确实现类型 "extension"函数

标签 c++

对于我正在开发的二进制协议(protocol)库,我广泛使用了 StrongType<T> ,我正在将这个概念扩展到枚举。

我有一个 InBitStream实现逐位读取字节数组的对象,我的意思是,每个字段都可以以固定和预定义的位数从数组中读取。

例如,我可以读取 StrongType d 字段以 5 位存储,然后以这种方式存储其他 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,它会检查它是否为正数,而对于枚举,它必须检查最大值、最小值和一些内部无效值。

要求 ValidatedField 与类型具有相同的接口(interface),所以我无法组合它,也没有 virtual函数是允许的,因为类型从不以多态方式使用。

(模式应该类似于装饰器,也许)。

有什么想法吗?谢谢。

最佳答案

然后我找到了一个好的解决方案。

这是 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;
    }
};

这只是为验证类型创建一个标签。流运算符 >>> 是使用它调度的。 Type 模板类型用于公开嵌入类型,Validator 类型用作仿函数。验证器必须公开一个静态函数 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 .

按照维基百科页面中的示例重新排列代码,我修复了“静态”问题。

这是非常明确的代码:

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

关于c++ - 如何在 C++ 中正确实现类型 "extension"函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54236863/

相关文章:

c++ - 正在分配指针的测试类析构函数?

c++ - 将十六进制流转换为 GIF

c++ - 对 2dim vector 进行排序并保留索引

c++ - OpenCV:基于三角选择倾斜图像

c# - 使用 c# 将委托(delegate)传递给非托管代码中的回调函数

c++ - 指向 QList 的指针 - at() 与 [] 运算符

c# - 性能瓶颈 - 使用 Visual Studio

c++ - 类和类成员的联系

c++ - 在 KV 存储上运行 TPC-C(或 YCSB)基准测试

c++ - 使用 C++ 模板时表达约束