c++ - 强制内部 API 的调用者使用固定大小类型?

标签 c++ type-conversion portability

我们有一些如下所示的代码:

class Serializer
{
public:
    template<class Type> void Write(const Type& value)
    {
        internal_write((byte*)value, sizeof(Type));
    }

    // some overloads of Write that take care of some tricky type we have defined

private:
    // implementation of internal_write
};

正如人们可能猜测的那样,这会将数据写入磁盘。我们有类似的 Read 函数,或多或少地将一些字节转换为类型。虽然不像它应有的那样健壮,但它确实有效,因为我们在与读取相同的平台上写入——这意味着我们写入的字节与我们需要读取的字节相匹配。

我们现在正在转向支持多个平台。我们在几个地方都有这样的代码:

unsigned long trust_me_this_will_be_fine = get_unsigned_long();
a_serializer.Write(trust_me_this_will_be_fine);

这在当前世界中工作得很好,但如果我们假设我们想要支持的平台之一有 unsigned long一个是 32 位,另一个是 64 位,我们都被淹没了。

我想更改Serializer::Write仅采用显式大小的类型作为参数。我想到了这一点:

class Serializer
{
public:
   void Write(uint32_t value) { ... }
   void Write(uint64_t value) { ... }
};

但我认为这并不能真正解决问题,因为在 32 位系统上,unsigned long会自动转换成 uint32_t但在 64 位系统上它将自动转换为 uint64_t .

我真正想要的是 Write(uint32_t) 接受 uint32_t 类型的参数——这意味着它需要显式的强制转换。我认为没有直接的方法可以做到这一点 - 如果我错了,请告诉我。

除此之外,我可以想出两种方法来解决这个问题。

  1. 声明(但不定义) Serializer::Write 的私有(private)版本对于可以自动转换为我们支持的类型的每种类型。
  2. 不要接受uint32_t直接,但是一个持有 uint32_t 的类并且只有 uint32_t 的显式构造函数.

选项 2 看起来像这样:

class only_uint32
{
public:
    uint32_t _value;
    explicit only_uint32(uint_32 value) : _value(value) { }
};

class Serializer
{
public:
    void Write(only_uint32 value) { ... }
};

然后调用代码如下所示:

unsigned long might_just_work = get_unsigned_long();
a_serializer.Write(static_cast<uint32_t>(might_just_work)); // should work, and be explicitly sized.
a_serializer.Write(might_just_work); // won't compile

我想很多人都已经解决了此类问题。有没有我没有想到的首选方法?我的一个想法是可怕的、伟大的、可行的还是什么?

PS:是的,我知道这是一篇超长的文章。不过,这是一个有点复杂和详细的问题。

更新:

感谢您的想法和帮助。我认为我们将采用这样的解决方案:

class Serializer
{
public:
    template<class Type> void Write32(const Type& value)
    {
        static_assert(sizeof(Type) == 4, "Write32 must be called on a 32-bit value.");
        internal_write(reinterpret_cast<byte*>(value), 4);
    }
    // overloads like Write64 and various tricky types as before.

private:
    // implementation of internal_write
};

这是一个相当低成本(就工程时间而言)的解决方案,它成功地将您实际保存的内容推送给调用者,并迫使调用者知道他们在调用什么。

最佳答案

你可以这样做:

template<typename T>
class MyClass {
public:
    static_assert(sizeof(T) == sizeof(uint32_t), "Invalid type");
    MyClass(T t) : data(t) { }

private:
    uint32_t data;
};

或者,如果您只想接受 uint32_t:

template<typename T>
class MyClass {
public:
    static_assert(is_same<T, uint32_t>::value, "Invalid type");
    MyClass(T t) : data(t) { }

private:
    uint32_t data;
};

关于c++ - 强制内部 API 的调用者使用固定大小类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9107690/

相关文章:

c++ - 使用非 constexpr 函数设置 constexpr 变量(但可以在编译时计算)

c++ - 在 C++ 中通过零扩展将 char 转换为 int

c# - 为什么动态转换会抛出异常?

c++ - boost Python 可移植性问题

vmware - 是否可以创建可移植虚拟机?

c# - 无法引用 UWP Windows.Devices.Portable

c++ - 如何在 VS C++ 中使用 IA32 指令 'fabs'?

c++ - 如何解决由递归函数引起的堆栈溢出错误? C++

python - make 在 make 调用期间找不到 OpenCV 库

Rust:为 usize、u64、u32 等实现 From<_>