$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
Subject: [boost] How best to implement a bitfield in C++ 14?
From: Niall Douglas (s_sourceforge_at_[hidden])
Date: 2016-02-03 04:01:09
Dear Boost,
As part of the AFIO v2 rewrite I've been trying to improve on how 
AFIO v1 did bitfields by making better use of constexpr and the type 
system to make usage more natural. I'd appreciate feedback on my 
efforts.
AFIO v1 has an example of usage at https://goo.gl/oVLIjU or 
https://gist.github.com/ned14/9ef2a9d00da0ffc877b8 and it took the 
following form:
enum class flag : size_t
{
  none=0,
  delete_on_close=1,
  disable_safety_fsyncs=2
};
BOOST_AFIO_DECLARE_CLASS_ENUM_AS_BITFIELD(flag)
The BOOST_AFIO_DECLARE_CLASS_ENUM_AS_BITFIELD macro declares all the 
sensible global overloads you'd expect, is type safe and you can use 
it without surprise except in one single instance: testing for 
emptiness. The problem is that you cannot declare as a global 
operator an explicit operator bool nor member functions on enums, so 
one cannot do if(f) though if(!f) is fine. In AFIO v1, I used if(!!f) 
and if(!!(f & flag::foo)) everywhere, which is fine if a little 
abtuse.
AFIO v2's current bitfield has an example of usage at 
https://goo.gl/LsjSGD or 
https://gist.github.com/ned14/89ee39c6b8eb5254116a and it takes the 
following form:
struct flag : bitwise_flags<flag>
{
  flag() = default;
  constexpr flag(bitwise_flags<flag> v) noexcept : 
bitwise_flags<flag>(v) { }
  static constexpr auto none(){ return bit(0);}
  static constexpr auto delete_on_close(){ return bit(1); }
  static constexpr auto disable_safety_fsyncs(){ return bit(2); }
};
Here the bitwise_flags<> base class does all the implementation 
magic, so once again you can use it without surprise except for the 
obvious clanger - bitfield items are now functions, so instead of the 
more natural:
  flag f(flag::disable_safety_fsyncs);
  flag f2(f&flag::none);
  f2|=flag::delete_on_close;
  constexpr flag f3(flag::disable_safety_fsyncs);
  constexpr flag f4(f3&flag::none);
You are stuck with:
  flag f(flag::disable_safety_fsyncs());
  flag f2(f&flag::none());
  f2|=flag::delete_on_close();
  constexpr flag f3(flag::disable_safety_fsyncs());
  constexpr flag f4(f3&flag::none());
I'll admit I started this with the static constexpr flag values being 
member variables which always works on MSVC and on GCC and clang when 
the optimiser is running. Unfortunately both GCC and clang appear to 
be extremely conservative about when a constexpr variable is 
ODR-used, indeed despite my original design of an unavoidable 
lvalue-to-rvalue conversion intended to force ODR-used to be off both 
compilers go ahead and enforce ODR-used anyway which generates 
undefined reference errors for the storage of the static member 
variables :( If you'd like to read more about that, and the WG21 DR 
relating to [basic.def.odr], see 
https://stackoverflow.com/questions/8016780/undefined-reference-to-sta
tic-constexpr-char/28846608#28846608.
So, do Boosters think we can actually make a C++ 14 bitfield which:
1. Is typesafe, so not a C bitfield.
2. Is convenient for programmers to declare (i.e. little boilerplate 
in a specific bitfield declaration).
3. Works as you'd expect a bitfield to work, including 
bitfield::flag.
4. if(bf) works.
5. Is 100% constexpr and generates zero runtime overhead.
My thanks in advance for any advice.
Niall
-- ned Productions Limited Consulting http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/