【问题标题】:how to pass a bitfield in by reference如何通过引用传递位域
【发布时间】:2020-10-14 06:16:34
【问题描述】:

请注意已经存在一个标题几乎完全相同的问题,但提出了一个非常不同的问题。

假设我想要一个将位域引用或指针作为参数的方法。这是不合法的,但也许可以举个例子来说明:

class Foo {

  unsigned a:2, b:2, c:2;

  bool Bar( unsigned* px:2 ) { *px = a; return true; };
}

Foo foo;
if ( foo.Bar( &foo.b ) )
    exit( EXIT_SUCCESS );

我可以把 Bar 写成一个宏:

#define BAR( pfoo, field ) ( ( (pfoo)->field = (pfoo)->a ), true )

Foo foo;
if ( BAR( &foo, b ) )
    exit( EXIT_SUCCESS );

在很多地方你可以用 C 语言编写一些这样的宏,现在你可以使用函数模板来处理。是否有模板解决方案可以在 C++11 或更高版本中合法编写上述 Bar() 方法?

【问题讨论】:

  • unsigned* px: 2 的假设示例无法解决问题,因为它仅包含大小信息,但您还需要单词中的位置信息,这说明了为什么不会这样有用的功能。
  • 替代方案是简单地将foo.a 作为unsigned 参数传递给您的方法,并将其分配给b。但也许您的示例过于简化,无法在您的实际用例中使用。无论哪种方式,都无法获取或引用位字段的地址。
  • @super 您建议的更改改变了问题太多。这需要 Bar 知道分配的目的地是什么。这个问题的关键是我们不知道,这就是为什么我们需要通过引用传递一些东西。
  • @FatihBAKIR: 无符号的假设示例 px: 2 不会解决问题,因为它只包含大小信息*...好吧,如果 C++ 支持这一点,它不会只包含尺寸信息,很明显!例如,该偏移量可能是 px 后面称为 _bitfield_offset_px 的不可见参数,并且对 px 的任何引用都会根据需要使用 <<>> 操作自动转换。如果他们愿意,我认为这很容易做到。
  • 这让我想起了专业化std::vector<bool>,这通常被认为是不走运或不知何故坏了。将单个 bool 元素压缩为位使它们可以通过普通指针或引用进行寻址。必须改用std::vector<bool>::reference。甚至没有提供std::vector&lt;&gt;::data()。 TL;DR:我认为位域的使用必须小心 - 它破坏了可能用于其他类型的通常应用程序。

标签: c++ bit-fields


【解决方案1】:

有可能以相当低效和迂回的方式拼凑一些充当位域引用的东西。

template<typename underlying>
struct bitfield_ref
{
    virtual underlying get() { return getter(); }
    virtual void set(underlying val) { setter(val); }
    bitfield_ref(std::function<underlying()> getter, std::function<void(underlying)> setter) :
      getter(getter), setter(setter) {}
    std::function<underlying()> getter;
    std::function<void(underlying)> setter;
};

#define BITFIELD_REF(s,m) bitfield_ref<decltype(s.m)>( \
      [&s]() { return s.m; }, \
      [&s](decltype(s.m) v) { s.m = v; })

可以这样使用

  struct moo
  {
      unsigned int a : 2;
      unsigned int b : 3;
  };

  unsigned int test(bitfield_ref<unsigned int> x)
  {
      x.set(3);
      return x.get() + 1;
  }

  int main()
  {
      moo m;
      std::cout << test(BITFIELD_REF(m, a)) << "\n";
  }

还可以通过定义转换运算符和赋值运算符(以及与之相关的所有复合赋值)来摆脱getset,为简洁起见省略。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-12
    • 2014-12-13
    • 2018-06-29
    • 2010-11-02
    • 2015-04-23
    相关资源
    最近更新 更多