【问题标题】:Variable class/struct structure? (Not template & not union?)变量类/结构结构? (不是模板也不是联合?)
【发布时间】:2016-07-25 19:19:21
【问题描述】:

我试过联合...

struct foo
{
    union
    {
        struct // 2 bytes
        {
            char var0_1;
        };
        struct // 5 bytes
        {
            char var1_1;
            int var1_2;
        };
    };
};

问题:联合做我想做的事,除了它们总是会占用最大数据类型的大小。在我的情况下,我需要 struct foo 进行一些初始化,以便我告诉它从两者中选择哪个结构(如果这甚至是合法的),如下所示。

所以在那之后,我尝试了类模板重载...

template <bool B>
class foo { }

template <>
class foo<true>
{
    char var1;
}

template <>
class foo<false>
{
    char var0;
    int var1;
}

问题:我对模板非常满意,而且我可以在 char 和 int 上使用相同的变量名,但问题在于语法。因为类是在编译时创建的,所以模板布尔变量需要是硬编码的常量,但在我的情况下,布尔变量需要在运行时由用户定义。

所以我需要两个“世界”中的一些东西。我怎样才能实现我想要做的事情?

!!注意:foo 类/结构稍后将被继承,因此如前所述,foo 的大小至关重要。

编辑#1:: 应用:

基本上,这将用于读取/写入(使用指针作为接口)特定的数据缓冲区,还允许我创建(类/结构的新实例)相同的数据缓冲区。您在上面看到的变量指定了长度。如果是较小的数据缓冲区,则长度以 char/byte 形式写入。如果它是一个更大的数据缓冲区,则第一个 char/byte 为 null 作为标志,而 int 指定长度。在长度之后,很明显实际数据随之而来,因此为什么要继承。班级规模是最重要的。我也需要吃蛋糕。

【问题讨论】:

  • 你想要完成什么?
  • 也许你可以看看 boost::any?
  • @NathanOliver 我将使用它作为读取/写入数据的指针,并初始化它的一个实例以写入新数据。 foo 将更像是一个共享界面。
  • 最好的办法是使用宏的__x86_64__ 等,或者通过UINTPTR_MAX 检查它的大小是 64 位长大小,还是 32 位长大小。然后使用size_t 作为您的会员类型。那应该保证它是指针的大小。可能有点开箱即用,或者您尝试做的事情的思考方向错误。

标签: c++ templates struct


【解决方案1】:

抽象层。

struct my_buffer_view{
  std::size_t size()const{
    if (!m_ptr)return 0;
    if (*m_ptr)return *m_ptr;
    return *reinterpret_cast<std::uint32_t const*>(m_ptr+1);
  }
  std::uint8_t const* data() const{
    if(!m_ptr)return nullptr;
    if(*m_ptr)return m_ptr+1;
    return m_ptr+5;
  }
  std::uint8_t const* begin()const{return data();}
  std::uint8_t const* end()const{return data()+size();}
  my_buffer_view(std::uint_t const*ptr=nullptr):m_ptr(ptr){}
  my_buffer_view(my_buffer_view const&)=default;
  my_buffer_view& operator=(my_buffer_view const&)=default;
private:
  std::uint8_t const* m_ptr=0;
};

任何地方都没有可变大小的数据。我可以为size etx 使用联合:

  struct header{
    std::uint8_t short_len;
    union {
      struct{
        std::uint32_t long_len;
        std::uint8_t long_buf[1];
      }
      struct {
        std::short_buf[1];
      }
    } body;
  };

但我只是做了指针运算。

将这样的缓冲区写入字节流完全是另一个问题。

【讨论】:

  • 这种方法对我的确切情况没有帮助(这确实非常非常具体),但它是一段很好的代码,我敢肯定会在更普遍的情况下有所帮助。感谢您的贡献。
【解决方案2】:

您的解决方案没有意义。考虑一下您的解决方案:您可以定义两个独立的类:fooTrue 和 fooFalse,其对应的成员完全相同,结果相同。

您可能正在寻找不同的解决方案作为继承。例如,您的 fooTrue 是 baseFoo ,而您的 fooFalse 是 derivedFoo ,前一个为 base 并用另一个 int 成员扩展它。

在这种情况下,您将多态性作为在运行时工作的方法。

【讨论】:

  • 你肯定有这个观点。我会看看,看看我如何将它应用到我想要实现的目标中。
【解决方案3】:

你不能一边吃蛋糕一边吃。

模板的意义在于特化发生在编译时。在运行时,类的大小是固定的(尽管是以实现定义的方式)。

如果您希望在运行时做出选择,那么您不能使用在编译时确定大小的机制。您将需要一种机制来满足这两种可能的需求。实际上,这意味着您的基类需要足够大以包含所有必需的成员 - 这基本上就是您基于联合的解决方案所发生的事情。

参考您的“!!NOTE”。你正在做的就是过早的优化。您正在尝试优化基类的大小,但没有任何证据(例如内存使用量的测量)证明大小差异对您的应用程序实际上很重要(例如,它会导致您的应用程序耗尽可用内存)。某事物将成为许多其他类的基础这一事实本身并不足以担心它的大小。

【讨论】:

  • 您拥有一个以特定方式工作的协议这一事实并不意味着您需要在程序中调整数据结构的大小。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-13
  • 2015-02-06
  • 1970-01-01
  • 1970-01-01
  • 2013-12-11
  • 1970-01-01
相关资源
最近更新 更多