как передать битовое поле по ссылке

#c #bit-fields

#c #битовые поля

Вопрос:

Обратите внимание, что вопрос с почти таким же названием уже существует, но задает совсем другой вопрос.

Допустим, мне нужен метод, который принимает ссылку на битовое поле или указатель в качестве аргумента. Это незаконно, но, возможно, пример прояснит:

 class Foo {

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

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

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

Я мог бы написать Bar как макрос:

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

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

Многие места, где вы бы написали какой-нибудь такой макрос на C, теперь можно обрабатывать с помощью шаблонов функций. Существует ли шаблонное решение для написания вышеупомянутого метода Bar() на законных основаниях в C 11 или более поздней версии?

Комментарии:

1. Гипотетический пример с unsigned* px: 2 не решил бы проблему, поскольку он содержит только информацию о размере, но вам также понадобится информация о позиции в word, которая показывает, почему это не было бы полезной функцией.

2. Альтернативой было бы просто передать foo.a ваш метод в качестве unsigned параметра и назначить его b . Но, возможно, ваш пример слишком упрощен, чтобы это работало в вашем реальном варианте использования. В любом случае невозможно получить адрес или сделать ссылку на битовое поле.

3. @super предложенное вами изменение слишком сильно меняет вопрос. Для этого Bar потребуется знать, каково назначение назначения. Ключевым моментом в этой проблеме является то, что мы не знаем , и именно поэтому нам нужно передать что-то по ссылке.

4. @FatihBAKIR: Гипотетический пример с беззнаковым px: 2 не решил бы проблему, поскольку он содержит только информацию о размере *… Ну, если бы C поддерживал это, он содержал бы не только информацию о размере, ясно! Это смещение может, например, быть невидимым параметром после вызова px _bitfield_offset_px , и любая ссылка на px автоматически преобразуется с << >> помощью операций или по мере необходимости. Я думаю, это было бы легко сделать, если бы им захотелось это сделать.

5. Это напоминает мне специализацию std::vector<bool> , которая обычно считается неудачной или как-то сломанной. Сжатие отдельных bool элементов в виде битов делает их адресуемыми с помощью простого указателя или ссылки. Вместо этого должен использоваться std::vector<bool>::reference . Это std::vector<>::data() даже не предусмотрено. TL; DR: Я считаю, что использование битовых полей должно выполняться с осторожностью — это нарушает обычные приложения, которые могут быть выполнены для других типов.

Ответ №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)>( 
      [amp;s]() { return s.m; }, 
      [amp;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";
  }
  

Кроме того, от него можно избавиться get , set определив оператор преобразования и оператор присваивания (и все сопутствующие ему составные присваивания), это опущено для краткости.