#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
определив оператор преобразования и оператор присваивания (и все сопутствующие ему составные присваивания), это опущено для краткости.