C++ Unordered Pair Type - c++

I'd like to create an unordered pair type in c++, that is, an unordered_set guaranteed to have exactly two elements. Here's what I've come up with, but the problem is if I use this approach, there's a heck of a lot more I have to override - each of the comparison operators, and so on. Is there a simpler way?
class unordered_pair : public std::pair<t, u>
{
public:
unordered_pair(t x, u y) : std::pair<t, u>(x,y) {};
bool operator ==(const unordered_pair<t,u>& rhs)
{
if ((this->first < this->second) ^ (rhs.first < rhs.second))
{
return this->second == rhs.first && this->first == rhs.second;
}
else
{
return this->first == rhs.first && this->second == rhs.second;
}
}
};

I would do something like
struct unordered_pair : std::pair<t, u>
{
bool swapped;
unordered_pair(t x, u y) :
std::pair<t, u>(x,y),
swapped(false);
{
sort();
}
void sort() {
swapped = first > second;
if (swapped)
std::swap(first, second);
}
std::pair<t, u> getOrig() {
if (swapped)
return std::pair<t,u>(second, first);
return std::pair<t, u>(first, second);
}
}
Then you just call sort() every time you change first or second; and all the comparison operators are obtained from the std::pair for free!
The motivation is that if you don't care about the ordering for comparisons, then you won't care about the ordering most of the time; Which will mean most of the time, you won't need to get the original item.
Edit: You state in the comments that we can assume t==u ... in that case I would suggest getting rid of t or u - and make it just std::pair<t, t>

Let's fill in some types into this template (which you omitted the template, there is no declaration of t or u), and see what it tries to instantiate
unordered_pair<int, std::string> pair, pair2;
bool operator ==(const unordered_pair<t,u>& rhs)
{
if ((this->first < this->second) ^ (rhs.first < rhs.second))
This is bool operator <(int, std::string) and bool operator <(std::string, int). These don't exist.
{
return this->second == rhs.first && this->first == rhs.second;
}
This is bool operator ==(int, std::string) and bool operator ==(std::string, int). These also don't exist.
else
{
return this->first == rhs.first && this->second == rhs.second;
}
}
You instead want one template type parameter. Try something like this
class bad_unordered_pair : public std::exception
{
const char * what() const { return "unordered_pair must have exactly two distinct values"; }
}
template <typename T>
std::pair<T, T> make_unordered_pair(T first, T second)
{
std::hash<T> hash;
if (first == second) throw bad_unordered_pair{};
if (hash(first) < hash(second)) return unordered_pair(first, second);
return unordered_pair(second, first);
}

Aside: I'm assuming that you meant
template<typename t>
class unordered_pair : public std::pair<t, t>
since it doesn't make sense for the members to be of different types if they should be interchangeable.
You could write a simple sorted() method, to ease writing these overloads:
private:
std::tuple<t const&, t const&> ordered() const noexcept
{
return (this->first < this->second)
? std::tie(this->first, this->second)
: std::tie(this->second, this->first);
}
};
Then implement == and < using that:
bool operator ==(const unordered_pair<t>& rhs) const noexcept
{
return ordered() == rhs.ordered();
}
bool operator <(const unordered_pair<t>& rhs) const noexcept
{
return ordered() < rhs.ordered();
}
and the other operators in terms of those:
bool operator !=(const unordered_pair<t>& rhs) const noexcept
{
return !(*this == rhs);
}
bool operator >(const unordered_pair<t>& rhs) const noexcept
{
return rhs < *this;
}
bool operator <=(const unordered_pair<t>& rhs) const noexcept
{
return !(rhs < *this);
}
bool operator >=(const unordered_pair<t>& rhs) const noexcept
{
return !(*this < rhs);
}
Alternatively, if you have C++20, then implement <=> instead:
template<typename T>
class unordered_pair : public std::pair<T, T>
{
public:
unordered_pair(T x, T y)
: std::pair<T, T>(x,y)
{}
std::strong_ordering operator<=>(const unordered_pair<T>& other)
{
return ordered() <=> other.ordered();
}
private:
std::tuple<T const&, T const&> ordered() const noexcept
{
return (this->first < this->second)
? std::tie(this->first, this->second)
: std::tie(this->second, this->first);
}
};
Or even absorb the helper into the operator:
std::strong_ordering operator<=>(const unordered_pair<T>& other)
{
auto ordered = [](unordered_pair<T> const& t) {
return (t.first < t.second)
? std::tie(t.first, t.second)
: std::tie(t.second, t.first);
};
return ordered(*this) <=> ordered(other);
}
Whichever approach you take, you'll want to be careful not to compare through base-class pointers, or you'll get inconsistent behaviour.

Related

C++ cast template type

Consider the following code snippet :
[[nodiscard]] bool operator==(const BasicIterator<const Type>& rhs) const noexcept {
if( this == &rhs ) {
return true;
}
return node_ == rhs.node_;
}
[[nodiscard]] bool operator==(const BasicIterator<Type>& rhs) const noexcept {
// how to call existing operator== implementation ??
//return operator==( rhs );
}
How should I use the same implementation for both operator==? Is it possible to call operator== <const Type> version from operator== <Type>?
Is there any cast for template types in this case?
Is Type a template? If not, maybe make it a template?
template <typename T>
[[nodiscard]] bool operator==(const BasicIterator<T>& rhs) const noexcept {
if( this == &rhs ) {
return true;
}
return node_ == rhs.node_;
}
If you do not want to expose this template to users, hide it somewhere and use in implementation:
private:
template <typename T>
[[nodiscard]] bool operator==(const BasicIterator<T>& lhs, const BasicIterator<T>& rhs) const noexcept {
if( &lhs== &rhs ) {
return true;
}
return lhs.node_ == rhs.node_;
}
public:
[[nodiscard]] bool operator==(const BasicIterator<const Type>& rhs) const noexcept {
return operator==<const Type>(*this, rhs);
}
[[nodiscard]] bool operator==(const BasicIterator<Type>& rhs) const noexcept {
return operator==<Type>(*this, rhs);
}

How to overload the assignment operator for a class that inherits from a template in c++

I have a given utility template class tagged. I had to declare 2 new structs using these template classes as follows.
tagged.h
#ifndef TAGGED_H
#define TAGGED_H
#include <iostream>
template<typename T, typename TAG>
class tagged
{
private:
T _value;
public:
tagged() : _value() { }
explicit tagged(const T& value) : _value(value) { }
// https://isocpp.org/wiki/faq/templates#template-friends
friend T& value(tagged<T, TAG>& st)
{
return st._value;
}
friend const T& value(const tagged<T, TAG>& st)
{
return st._value;
}
};
template<typename T>
struct equality
{
friend bool operator ==(const T& x, const T& y)
{
return value(x) == value(y);
}
friend bool operator !=(const T& x, const T& y)
{
return value(x) != value(y);
}
};
template<typename T>
struct ordered : equality<T>
{
friend bool operator <(const T& x, const T& y)
{
return value(x) < value(y);
}
friend bool operator <=(const T& x, const T& y)
{
return value(x) <= value(y);
}
friend bool operator >(const T& x, const T& y)
{
return value(x) > value(y);
}
friend bool operator >=(const T& x, const T& y)
{
return value(x) >= value(y);
}
};
These are the two structs i declared following the rules given by the assignment.
primitives.h
//Time
struct __declspec(empty_bases)Time : tagged<uint64_t, Time>, ordered<Time>, show_value<Time, int>{ using tagged::tagged; };
//Duration
struct __declspec(empty_bases)Duration : tagged<uint64_t, Duration>, ordered<Duration>, show_value<Duration, int> { using tagged::tagged; };
I succeeded in writing all other operators like + and - but i cant seem to solve how to overload += and -= I'm not allowed to change the objects in tagged.h I know assignment operators can only be member functions. Because of the way the template works i've tried casting 'const Time&' and const Duration& to non consts but that didnt seem to work. I've tried the examples you can find online about assigment operator overloading but the examples all overload in the template and not in the inherited class where I barely have write access to '_value' which is the value I should overwrite of reassign the pointer of.
Thanks
edit:
struct __declspec(empty_bases)Time : tagged<uint64_t, Time>, ordered<Time>, show_value<Time, int>
{
using tagged::tagged;
Time& operator+(const Duration& right) {
Time t = Time(value(*this) + value(right));
return t;
};
Time& operator+=(const Duration& right) {
(uint64_t&)(*this) = value(*this) + value(right);
return (*this);
};
};
//Duration
struct __declspec(empty_bases)Duration : tagged<uint64_t, Duration>, ordered<Duration>, show_value<Duration, int> {
using tagged::tagged;
Duration& operator+(const Duration& right) {
Duration d = Duration(value(*this) + value(right));
return d;
};
Time& operator+(const Time & right) {
Time t = Time(value(*this) + value(right));
return t;
};
Duration& operator-(const Time & right) {
Duration d = Duration(value(*this) - value(right));
return d;
};
Duration& operator-(const Duration & right) {
Duration d = Duration(value(*this) - value(right));
return d;
};
Duration& operator+=(const Duration& right) {
(uint64_t&)(*this) = (uint64_t&)(*this) + (uint64_t&)(right);
return (*this);
}
Duration& operator-=(const Duration& right) {
(uint64_t&)(*this) = value(*this) - value(right);
return (*this);
};
};
This is what I have now. Still have the same syntax errors that keep popping up. I dont know anymore lmao
From what I see you should be able to implement it using value() function; Since value returns by reference something like this should work:
Duration & operator+=(const Duration & right) {
value(*this) += value( right );
return *this;
}
Just be careful on the other operators (I'm looking at + and -) because you return references to temporal objects.
Duration & operator+(const Duration & right) { // this returns a reference to an object
Duration d = Duration( value( *this ) + value( right ) ); // this creates a temporal variable
return d; // you return a reference to d bu its lifetime is over -> undefined behavior I believe
}

Template class implementing comparison operators

It is a frequent task of mine to write all the overloaded comparison operators to a class, so I've written a template class which implements <,<=,>=,!= if the derived class implements == and <. It is working but features a lot of cast and the not that obvious "Curiously recurring template pattern", so I wonder if are there simpler solutions?
template <class Derived>
class Comparable
{
public:
bool operator!=(const Comparable<Derived>& other) {
return !(static_cast<Derived*>(this)->operator==
(*static_cast<const Derived*>(&other)));
}
bool operator<=(const Comparable<Derived>& other) {
return (static_cast<Derived*>(this)->operator==
(*static_cast<const Derived*>(&other)))
|| (static_cast<Derived*>(this)->operator<
(*static_cast<const Derived*>(&other)));
}
bool operator>(const Comparable<Derived>& other) {
return !(static_cast<Derived*>(this)->operator==
(*static_cast<const Derived*>(&other)))
&& !(static_cast<Derived*>(this)->operator<
(*static_cast<const Derived*>(&other)));
}
bool operator>=(const Comparable<Derived>& other) {
return !(static_cast<Derived*>(this)->operator<
(*static_cast<const Derived*>(&other)));
}
};
In case it is not obvious from the description in the comment:
template <typename T>
struct Comparable {
friend bool operator!=(T const & lhs, T const & rhs) { return !(lhs == rhs); }
friend bool operator> (T const & lhs, T const & rhs) { return rhs < lhs; }
// ...
};
class MyType : Comparable<MyType> {
int data;
friend bool operator==(MyType const & lhs, MyType const & rhs) {
return lhs.data == rhs.data;
}
friend bool operator< (MyType const & lhs, MyType const & rhs) {
return lhs.data < rhs.data;
}
public:
// ...
};
When the compiler encounters MyType a, b; a > b; lookup for the operator will end up doing ADL which will look inside MyType and Comparable<MyType> (as this is a base), where it will find the implementation you need: bool operator>(MyType const&, MyType const&).
The operators being free functions allows for a definition that is outside of the type that is being compared (in this case the base), while making those operators only available through ADL (one of the two arguments must be Comparable<MyType>). The use of a free function also provides type-symmetry, the compiler will allow implicit conversions on both sides, where in the case of a member function it would only allow conversions on the right hand side of the operator.
For completeness, a different trick that can be done is to provide the operators as templates in a namespace together with a tag that can be used to bring that namespace in for ADL purposes:
namespace operators {
template <typename T>
bool operator>(T const & lhs, T const & rhs) {
return rhs < lhs;
}
// rest of the operators come here
struct tag {};
}
class MyType : operators::tag {
int data;
friend bool operator<(T const & lhs, T const & rhs) {
return lhs.data < rhs.data;
}
//...
};
The trick is basically the same, except that in this case the operators are not found inside the base, but in a namespace that is associated with it. This solution is a bit less nice than the previous one, as it is open to different forms of misuse, including using namespace operators; that would make the templated operators available for all types.

My vector is sorted and yet I'm getting a "sequence not ordered" error

Are there situations in which std::sort fails?
I've got a std::vector<KeyValPair<T>> queue with which I do the following
std::sort(queue.begin(), queue.end());
std::pair<iterator, iterator> match =
std::equal_range(queue.begin(), queue.end(), cost);
Exactly that. And then sometimes, not always, I get a "sequence not ordered" error.
The documentation describes sort and equal_range as using the same comparison functions, so I am confused how the vector could become unordered.
The vector type is the following class with custom comparison operators.
template<typename T>
class KeyValPair: public std::pair<double, T>
{
public:
KeyValPair(double d, T t): std::pair<double, T>(d, t){};
bool operator<(const KeyValPair<T>& rhs) const
{
return first < rhs.first;
}
bool operator==(const KeyValPair<T>& rhs) const
{
return second == rhs.second;
}
};
template<typename T>
bool operator< (const KeyValPair<T>& lhs, const double& rhs) {return lhs.first < rhs;};
template<typename T>
bool operator< (const double& lhs, const KeyValPair<T>& rhs) {return lhs < rhs.first;};
Could the comparison function be failing somehow? What else can cause this error?
As first psychically detected by #ecatmur, your problem is you are using < on doubles, and one or more of your doubles is a NaN.
A safe double ordering follows:
struct safe_double_order {
bool operator()(double lhs, double rhs) const {
if ((lhs != lhs) || (rhs != rhs)) // NaN detector
return (lhs!=lhs)>(rhs!=rhs); // order NaN less than everything, including -infinity
return lhs < rhs;
}
};
Next, we can write a key-sorter:
template<class K, class O=std::less<K>>
struct key_sorter {
struct helper {
K const& k;
helper( K const& o ):k(o) {}
template<typename V>
helper( std::pair<K, V> const& o ):k(o.first) {}
bool operator<( helper const& o ) const {
return O{}( k, k.o );
}
};
bool operator()( helper lhs, helper rhs ) const {
return lhs < rhs;
}
};
which passed a key-type and an optional ordering functor lets you search/sort std::pair<Key,?> with Key types directly.
std::vector< std::pair<double, X> > vec;
std::sort( vec.begin(), vec.end(), key_sorter<double, safe_double_order>{} );
auto match = std::equal_range( vec.begin(), vec.end(), value, key_sorter<double, safe_double_order>{} );
There are some C++11isms above, but the general design should be clear if you are using C++03.

why isn't my implicit ctor invoked in following

With the following template to try to make C++ 11/14's new class-enum work as-desired, I find that the following code doesn't even try to invoke the implicit ctor to use a nonmember template that would fit by VS2013 update 1:
BitTest is defined as:
template <typename enumT>
bool BitTest(const EnumeratedFlags<enumT>& lhs, const EnumeratedFlags<enumT>& rhs)
{
return (lhs & rhs);
}
testing code with anomalies:
enum class Flags { None = 0x00, CanChangeDataSources = 0x01, RequiresExclusiveAccess = 0x02 };
EnumeratedFlags<Flags> lhs(Flags::CanChangeDataSources);
// ... the following fails to even attempt to convert the Foo::Flags
if (BitTest(lhs, Flags::CanChangeDataSources)) { DoSomething(); }
// this compiles, but I don't know why it's necessary (and this is annoying and ugly)...
if (BitTest(lhs, EnumeratedFlags<Flags>(Flags::CanChangeDataSources))) { DoSomething(); }
Here is the template definition I am currently attempting to use:
template <typename enumT>
class EnumeratedFlags
{
public:
typedef enumT enum_type;
typedef typename std::underlying_type<enumT>::type store_type;
// constructors
EnumeratedFlags()
: m_bits(0)
{
}
EnumeratedFlags(enum_type flag)
: m_bits(static_cast<store_type>(flag))
{
}
explicit EnumeratedFlags(store_type value)
: m_bits(value)
{
}
EnumeratedFlags(const std::initializer_list<enum_type> & initializers)
: m_bits(0)
{
for (auto flag : initializers)
m_bits |= static_cast<store_type>(flag);
}
// operators
operator std::string () const
{
return to_string();
}
bool operator [] (enum_type flag) const
{
return test(flag);
}
store_type operator * () const
{
return m_bits;
}
operator bool () const
{
return m_bits != store_type(0);
}
// explicit accessors
store_type bits() const
{
return m_bits;
}
std::string to_string() const
{
std::string str(size(), '0');
for (size_t x = 0; x < size(); ++x)
str[size() - x - 1] = (m_bits & (1 << x) ? '1' : '0');
return str;
}
EnumeratedFlags & set(enum_type flag)
{
BitSet(m_bits, static_cast<store_type>(flag));
return *this;
}
EnumeratedFlags & set_if(enum_type flag, bool set_or_clear)
{
BitSetIf(m_bits, static_cast<store_type>(flag), set_or_clear);
return *this;
}
EnumeratedFlags & clear()
{
m_bits = store_type(0);
return *this;
}
EnumeratedFlags & flip()
{
m_bits = ~m_bits;
return *this;
}
EnumeratedFlags & flip(enum_type flag)
{
m_bits ^= static_cast<store_type>(flag);
return *this;
}
size_t count() const
{
// http://www-graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan
store_type bits = m_bits;
size_t total = 0;
for (; bits != 0; ++total)
{
bits &= bits - 1; // clear the least significant bit set
}
return total;
}
size_t size() const
{
// one character per possible bit
return sizeof(enum_type) * 8;
}
bool test(enum_type flag) const
{
return BitTest(m_bits, static_cast<store_type>(flag));
}
bool any() const
{
return m_bits != 0;
}
bool none() const
{
return m_bits == 0;
}
private:
store_type m_bits;
};
template <class charT, class traits, typename enumT>
std::basic_ostream<charT, traits> & operator << (std::basic_ostream<charT, traits> & os, const EnumeratedFlags<enumT> & flags)
{
return os << flags.to_string();
}
template <typename enumT>
EnumeratedFlags<enumT> operator & (const EnumeratedFlags<enumT>& lhs, const EnumeratedFlags<enumT>& rhs)
{
return EnumeratedFlags<enumT>(lhs.bits() & rhs.bits());
}
template <typename enumT>
EnumeratedFlags<enumT> operator | (const EnumeratedFlags<enumT>& lhs, const EnumeratedFlags<enumT>& rhs)
{
return EnumeratedFlags<enumT>(lhs.bits() | rhs.bits());
}
template <typename enumT>
EnumeratedFlags<enumT> operator ^ (const EnumeratedFlags<enumT>& lhs, const EnumeratedFlags<enumT>& rhs)
{
return EnumeratedFlags<enumT>(lhs.bits() ^ rhs.bits());
}
template <typename enumT>
bool BitTest(const EnumeratedFlags<enumT>& lhs, const EnumeratedFlags<enumT>& rhs)
{
return (lhs & rhs);
}
Basically, I would have thought that any free function in the form of X (const T & lhs, const T & rhs) would use up to one user-defined conversion to find a valid invocation of BitTest<>(), above. Instead, I have to explicitly state the conversion in my above code to get the compiler to use this function, which vastly reduces the expressive power of template class EnumeratedFlags<>.
In general, C++ drives me nuts that there isn't a good way to use bits that combines all of the features and good programming habits of using a scoped enum (enum class Foo) and bit-fields (or a similar named set of bits) and make using them very easy for the client-programmer while retaining basic sanity checking from the compiler (won't auto-convert to a numeric type or vice-verse). Seems like a more comprehensive improvement in the language spec is required to make a bit-field enum that really shines... or am I missing something?
From ยง14.8.1/6 [temp.arg.explicit]
Implicit conversions (Clause 4) will be performed on a function argument to convert it to the type of the corresponding function parameter if the parameter type contains no template-parameters that participate in template argument deduction.
In your example the second argument to BitTest() does participate in template argument deduction, hence no implicit conversion is attempted and the compiler is unable to convert the type Flags to const EnumeratedFlags<Flag>&.
You could solve it by converting the second parameter type to a non-deduced context, thus preventing it from participating in template argument deduction.
template <typename enumT>
bool BitTest(const EnumeratedFlags<enumT>& lhs,
const EnumeratedFlags<typename EnumeratedFlags<enumT>::enum_type>& rhs)
{
return (lhs & rhs);
}
Live demo
Of course, the other solution is to provide these overloads instead
template <typename enumT>
bool BitTest(const EnumeratedFlags<enumT>& lhs,
enumT rhs)
{
return (lhs & EnumeratedFlags<enumT>(rhs));
}
template <typename enumT>
bool BitTest(enumT lhs,
const EnumeratedFlags<enumT>& rhs)
{
return BitTest(rhs, lhs);
}
My question is already answered above. However, this has been bothering me forever, so I was able to leverage everyone's responses and came up with, what I think is for the first time, a mechanism that I really like!
This gives me a way to use C++ enumerations to store bit flag values, and then to logically bit-manipulate them at will, while never losing type information or the compiler's assistance with making sure that I fall into the pit of success. :)
I hope this helps you too!
(Note: this code compiles and runs properly under VS2013 update 1)
#pragma once
#include <type_traits>
// This is my ongoing attempt to make a really solid enumeration facility in C++11/14
//
// What I hate about C++98 (and older) enum
// - lack of namespace scoping of the non-class enum (name collisions everywhere)
// - auto conversion to numeric types (int i = MyEnumConstant), but no conversion back again (so supports losing info, but restricts regaining it)
//
// What I hate about C++11/14 built-in `enum class X`
// - having to constantly cast in order to treat them (now neither direction works)
// - no built-in mechanism to treat enumerated values as bits or bit-flags
template <typename enum_type>
class bitflag_enum
{
public:
// expose our underlying types
typedef enum_type enum_type;
typedef typename std::underlying_type<enum_type>::type store_type;
// constructors
bitflag_enum()
: m_bits(0)
{
}
bitflag_enum(enum_type flag)
: m_bits(static_cast<store_type>(flag))
{
}
explicit bitflag_enum(store_type value)
: m_bits(value)
{
}
// operators
operator bool() const
{
return m_bits != store_type(0);
}
// explicit accessors
store_type bits() const
{
return m_bits;
}
private:
store_type m_bits;
};
// because implicit conversion isn't considered if a type participates in template type deduction,
// we've defined both homogeneous and heterogeneous operators here for bitflag_enum<enum_type> and enum_type
// hence we define logical operators &, |, ^ and comparisons for TxT, TxU, UxT (where T is bitflag_enum<enum_type>, and U is enum_type)
template <typename enum_type>
bool operator != (bitflag_enum<enum_type> lhs, bitflag_enum<enum_type> rhs)
{
return bitflag_enum<enum_type>(lhs.bits() != rhs.bits());
}
template <typename enum_type>
bool operator != (bitflag_enum<enum_type> lhs, enum_type rhs)
{
using store_type = std::underlying_type<enum_type>::type;
return bitflag_enum<enum_type>(lhs.bits() != static_cast<store_type>(rhs));
}
template <typename enum_type>
bool operator != (enum_type lhs, bitflag_enum<enum_type> rhs)
{
using store_type = std::underlying_type<enum_type>::type;
return bitflag_enum<enum_type>(static_cast<store_type>(lhs) != rhs.bits());
}
template <typename enum_type>
bool operator == (bitflag_enum<enum_type> lhs, bitflag_enum<enum_type> rhs)
{
return bitflag_enum<enum_type>(lhs.bits() == rhs.bits());
}
template <typename enum_type>
bool operator == (bitflag_enum<enum_type> lhs, enum_type rhs)
{
using store_type = std::underlying_type<enum_type>::type;
return bitflag_enum<enum_type>(lhs.bits() == static_cast<store_type>(rhs));
}
template <typename enum_type>
bool operator == (enum_type lhs, bitflag_enum<enum_type> rhs)
{
using store_type = std::underlying_type<enum_type>::type;
return bitflag_enum<enum_type>(static_cast<store_type>(lhs) == rhs.bits());
}
template <typename enum_type>
bitflag_enum<enum_type> operator & (bitflag_enum<enum_type> lhs, bitflag_enum<enum_type> rhs)
{
return bitflag_enum<enum_type>(lhs.bits() & rhs.bits());
}
template <typename enum_type>
bitflag_enum<enum_type> operator & (bitflag_enum<enum_type> lhs, enum_type rhs)
{
using store_type = std::underlying_type<enum_type>::type;
return bitflag_enum<enum_type>(lhs.bits() & static_cast<store_type>(rhs));
}
template <typename enum_type>
bitflag_enum<enum_type> operator & (enum_type lhs, bitflag_enum<enum_type> rhs)
{
using store_type = std::underlying_type<enum_type>::type;
return bitflag_enum<enum_type>(static_cast<store_type>(lhs)& rhs.bits());
}
template <typename enum_type>
bitflag_enum<enum_type> operator | (bitflag_enum<enum_type> lhs, bitflag_enum<enum_type> rhs)
{
return bitflag_enum<enum_type>(lhs.bits() | rhs.bits());
}
template <typename enum_type>
bitflag_enum<enum_type> operator | (bitflag_enum<enum_type> lhs, enum_type rhs)
{
using store_type = std::underlying_type<enum_type>::type;
return bitflag_enum<enum_type>(lhs.bits() | static_cast<store_type>(rhs));
}
template <typename enum_type>
bitflag_enum<enum_type> operator | (enum_type lhs, bitflag_enum<enum_type> rhs)
{
using store_type = std::underlying_type<enum_type>::type;
return bitflag_enum<enum_type>(static_cast<store_type>(lhs) | rhs.bits());
}
template <typename enum_type>
bitflag_enum<enum_type> operator ^ (bitflag_enum<enum_type> lhs, bitflag_enum<enum_type> rhs)
{
return bitflag_enum<enum_type>(lhs.bits() ^ rhs.bits());
}
template <typename enum_type>
bitflag_enum<enum_type> operator ^ (bitflag_enum<enum_type> lhs, enum_type rhs)
{
using store_type = std::underlying_type<enum_type>::type;
return bitflag_enum<enum_type>(lhs.bits() ^ static_cast<store_type>(rhs));
}
template <typename enum_type>
bitflag_enum<enum_type> operator ^ (enum_type lhs, bitflag_enum<enum_type> rhs)
{
using store_type = std::underlying_type<enum_type>::type;
return bitflag_enum<enum_type>(static_cast<store_type>(lhs) ^ rhs.bits());
}
// The only missing pieces above are for the UxU cases
// we allow you to have those by defining a specialization of is_bitflag_enum<>, as follows:
//
// template <> struct is_bitflag_enum<YourEnumType> : std::true_type { };
//
// However, by default, no other types will convert to an bitflag_enum<> unless you explicitly say you want it
//
// If you have asked for them, then you can use MyEnum::ValueX | MyEnum::ValueY and that will produce a bitflag_enum<MyEnum>
// so your code can simply use your enumeration values with scope and as-if they were bit flags as you would think you could
// don't mess up existing enumerations or types by defining these global operators on every existing type!
template <typename enum_type> struct is_bitflag_enum : std::false_type { };
template <typename enum_type>
typename std::enable_if<is_bitflag_enum<enum_type>::value, bitflag_enum<enum_type>>::type
operator & (enum_type lhs, enum_type rhs)
{
using store_type = std::underlying_type<enum_type>::type;
return bitflag_enum<enum_type>(static_cast<store_type>(lhs) & static_cast<store_type>(rhs));
}
template <typename enum_type>
typename std::enable_if<is_bitflag_enum<enum_type>::value, bitflag_enum<enum_type>>::type
operator | (enum_type lhs, enum_type rhs)
{
using store_type = std::underlying_type<enum_type>::type;
return bitflag_enum<enum_type>(static_cast<store_type>(lhs) | static_cast<store_type>(rhs));
}
template <typename enum_type>
typename std::enable_if<is_bitflag_enum<enum_type>::value, bitflag_enum<enum_type>>::type
operator ^ (enum_type lhs, enum_type rhs)
{
using store_type = std::underlying_type<enum_type>::type;
return bitflag_enum<enum_type>(static_cast<store_type>(lhs) ^ static_cast<store_type>(rhs));
}