constexpr inline T operator@(T a, T b) { return static_cast<T>(static_cast<UT>(a) @ static_cast<UT>(b));
}
constexpr inline T operator@=(T &a, T b) {
return reinterpret_cast<T &>(reinterpret_cast<UT &>(a) @= static_cast<UT>(b));
}
constexpr inline T operator~(T a) {
return static_cast<T>(static_cast<UT>(a) ^ static_cast<UT>(all));
}
constexpr inline bool operator==(T a, T b) {
return static_cast<UT>(a) == static_cast<UT>(b);
}
constexpr inline bool operator!=(T a, T b) {
return !(a == b);
}
constexpr inline bool operator<=(T a, T b) {
return (a & ~b) == static_cast<T>(0);
}
const inline bool operator<(T a, T b) {
return a <= b && a != b;
}
const inline bool operator>=(T a, T b) {
return b <= a;
}
const inline bool operator>(T a, T b) {
return b < a;
}
const inline operator bool(T a) {
return static_cast<UT>(a);
}
enums and enum classesThere are no bit operations.To use the enumeration as flags, values outside the list of tags are needed.There are no subset operations.
> constexpr inline bool operator<=(T a, T b) {
> return (a & ~b) == static_cast<T>(0);
> }
I'm not sure that ordering operations make sense. (Only if you need to
use them as keys in e.g. std::map.) I don't see that there is a logical
meaning to an ordering comparison of flags.
On 2015–02–02, at 6:55 PM, adrien courdavault <adrien...@gmail.com> wrote:HelloI agree with the problem list, but I think the solmution here is maybe more interesting for bit masks with typed enums:
HelloI agree with the problem list, but I think the solmution here is maybe more interesting for bit masks with typed enums:https://www.justsoftwaresolutions.co.uk/cplusplus/using-enum-classes-as-bitfields.html
which requires only the include of a header in the enum class header and a definition for SFINAE to specify if the overloads of bitwise operators should be implemented for the type.
On Mon, Feb 2, 2015 at 5:55 AM, adrien courdavault <adrien...@gmail.com> wrote:It is unfortunate that the opt-in flag can't just be part of the enum:HelloI agree with the problem list, but I think the solmution here is maybe more interesting for bit masks with typed enums:https://www.justsoftwaresolutions.co.uk/cplusplus/using-enum-classes-as-bitfields.html
which requires only the include of a header in the enum class header and a definition for SFINAE to specify if the overloads of bitwise operators should be implemented for the type.
#include <type_traits>
enum class Breakfast {
enable_bitwise_ops = 1, // give me the ops!
GreenEggs = 0x1,
Ham = 0x2
};
template<typename E>
typename std::enable_if<E::enable_bitwise_ops,E>::type
operator|(E lhs,E rhs){
typedef typename std::underlying_type<E>::type underlying;
return static_cast<E>(
static_cast<underlying>(lhs) | static_cast<underlying>(rhs));
}
int main() {
// your code goes here
Breakfast b = Breakfast::GreenEggs | Breakfast::Ham;
return 0;
}Unfortunately doesn't work. :-(Or maybe I didn't try hard enough? Is there something I can put in the enable-if to detect that enable_bitwise_ops is part of the enum?(Of course, you could also argue that it isn't the best solution - since it makes 'enable_bitwise_ops' a Breakfast value. But it is slightly nicer (to declare) than specializing a template.)
Tony
On 2015–02–04, at 4:03 AM, Tony V E <tvan...@gmail.com> wrote:Works now. Still questionable.
namespace mystuff {enum class Breakfast {
GreenEggs = 0x1,
Ham = 0x2
};
#include <cstdio>
#include <cstdint>
#define FLAG_CONCAT2(x, y) x ## y
#define FLAG_CONCAT(x, y) FLAG_CONCAT2(x, y)
#define FLAG(name) \
FLAG_CONCAT(DUMMY_FLAG_, __LINE__), \
name = static_cast<decltype(FLAG_CONCAT(DUMMY_FLAG_, __LINE__))>( \
FLAG_CONCAT(DUMMY_FLAG_, __LINE__) ? \
((FLAG_CONCAT(DUMMY_FLAG_, __LINE__) - 1) << 1) : 1)
enum class Meow : std::uint8_t
{
FLAG(Test0),
FLAG(Test1),
FLAG(Test2),
FLAG(Test3),
FLAG(Test4),
FLAG(Test5),
FLAG(Test6),
FLAG(Test7),
};
int main()
{
std::printf("%d %d %d %d %d %d %d %d\n",
static_cast<int>(Meow::Test0), static_cast<int>(Meow::Test1),
static_cast<int>(Meow::Test2), static_cast<int>(Meow::Test3),
static_cast<int>(Meow::Test4), static_cast<int>(Meow::Test5),
static_cast<int>(Meow::Test6), static_cast<int>(Meow::Test7));
return 0;
}
On 2015–02–04, at 9:21 AM, Myriachan <myri...@gmail.com> wrote:It's a horrible hack, but it's actually possible with macros to automate the process of determining the next flag in bitfield enums.
Tony V E <tvan...@gmail.com> writes:
[...]
| template<typename E>
| typename std::enable_if<E::enable_bitwise_ops,E>::type
^^^^^^^^^^^^^^^^^^^^^
Just allow it to be well-behaved enums.
You can add the operators as has been discussed for the bitmask operators.
Implicit conversions seem wrong for a strong typedef, IMHO. The lack of such is the chief benefit over a normal typedef.
Initialisation might be an issue, but you could easily do a cast or write a factory function.
Anthony
On 2015–02–18, at 3:51 AM, Hyman Rosen <hyman...@gmail.com> wrote:Strong typedef isn't the same as unit.
If I were to say (taking a page from Ada)typedef new int MyInt;
then I should be able to do
MyInt x{3};
x = x * x * x;
but if I had
typedef SI::Time MySec;
MySec x{3};
then
x = x * x * x;
should not compile.