From 4dec3f881b01b4087488d8dda36e1f5078825793 Mon Sep 17 00:00:00 2001 From: Dmitry Arkhipov Date: Tue, 2 Jun 2015 00:57:39 +0300 Subject: [PATCH 1/3] indentation --- include/flags/flags.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/flags/flags.hpp b/include/flags/flags.hpp index be69af22d..32dff0286 100644 --- a/include/flags/flags.hpp +++ b/include/flags/flags.hpp @@ -15,7 +15,7 @@ namespace flags { constexpr struct empty_t { - constexpr empty_t() noexcept {} + constexpr empty_t() noexcept {} } empty; From effcb7c3463577fa6507240eaa4c921bf32d30f9 Mon Sep 17 00:00:00 2001 From: Dmitry Arkhipov Date: Sun, 7 Jun 2015 06:54:12 +0300 Subject: [PATCH 2/3] more tests + bug fixes --- include/flags/flags.hpp | 100 ++++--------- include/flags/iterator.hpp | 2 +- test/Jamroot | 11 +- test/common.hpp | 14 ++ test/main-test.cpp | 8 +- test/should-compile.cpp | 147 +++++++++++++++++++ test/shouldnt-compile/allow-accidental.cpp | 9 ++ test/shouldnt-compile/common.hpp | 18 +++ test/shouldnt-compile/const-clear.cpp | 7 + test/shouldnt-compile/const-enum-assign.cpp | 7 + test/shouldnt-compile/const-erase-iter.cpp | 8 + test/shouldnt-compile/const-erase.cpp | 7 + test/shouldnt-compile/const-il-assign.cpp | 7 + test/shouldnt-compile/const-insert-iter.cpp | 8 + test/shouldnt-compile/const-insert.cpp | 7 + test/shouldnt-compile/const-set-uv.cpp | 7 + test/shouldnt-compile/const-swap.cpp | 8 + test/shouldnt-compile/implicit-bool-conv.cpp | 10 ++ test/shouldnt-compile/implicit-int-conv.cpp | 10 ++ test/shouldnt-compile/int-conversion.cpp | 6 + test/shouldnt-compile/iter-assign.cpp | 8 + test/shouldnt-compile/not-allowed.cpp | 10 ++ test/shouldnt-compile/wrong-enum.cpp | 6 + test/shouldnt-compile/wrong-flags.cpp | 6 + test/shouldnt-compile/wrong-iter.cpp | 11 ++ test/shouldnt-compile/wrong-variadic.cpp | 6 + 26 files changed, 369 insertions(+), 79 deletions(-) create mode 100644 test/common.hpp create mode 100644 test/should-compile.cpp create mode 100644 test/shouldnt-compile/allow-accidental.cpp create mode 100644 test/shouldnt-compile/common.hpp create mode 100644 test/shouldnt-compile/const-clear.cpp create mode 100644 test/shouldnt-compile/const-enum-assign.cpp create mode 100644 test/shouldnt-compile/const-erase-iter.cpp create mode 100644 test/shouldnt-compile/const-erase.cpp create mode 100644 test/shouldnt-compile/const-il-assign.cpp create mode 100644 test/shouldnt-compile/const-insert-iter.cpp create mode 100644 test/shouldnt-compile/const-insert.cpp create mode 100644 test/shouldnt-compile/const-set-uv.cpp create mode 100644 test/shouldnt-compile/const-swap.cpp create mode 100644 test/shouldnt-compile/implicit-bool-conv.cpp create mode 100644 test/shouldnt-compile/implicit-int-conv.cpp create mode 100644 test/shouldnt-compile/int-conversion.cpp create mode 100644 test/shouldnt-compile/iter-assign.cpp create mode 100644 test/shouldnt-compile/not-allowed.cpp create mode 100644 test/shouldnt-compile/wrong-enum.cpp create mode 100644 test/shouldnt-compile/wrong-flags.cpp create mode 100644 test/shouldnt-compile/wrong-iter.cpp create mode 100644 test/shouldnt-compile/wrong-variadic.cpp diff --git a/include/flags/flags.hpp b/include/flags/flags.hpp index 32dff0286..41905a890 100644 --- a/include/flags/flags.hpp +++ b/include/flags/flags.hpp @@ -97,9 +97,17 @@ template struct flags { constexpr bool operator!() const noexcept { return !val_; } - flags operator~() const noexcept { return flags(~val_); } + friend constexpr bool operator==(flags fl1, flags fl2) { + return fl1.val_ == fl2.val_; + } + + friend constexpr bool operator!=(flags fl1, flags fl2) { + return fl1.val_ != fl2.val_; + } + constexpr flags operator~() const noexcept { return flags(~val_); } + flags &operator|=(const flags &fl) noexcept { val_ |= fl.val_; return *this; @@ -131,6 +139,18 @@ template struct flags { return *this; } + friend constexpr flags operator|(flags f1, flags f2) noexcept { + return flags{f1.val_ | f2.val_}; + } + + friend constexpr flags operator&(flags f1, flags f2) noexcept { + return flags{f1.val_ & f2.val_}; + } + + friend constexpr flags operator^(flags f1, flags f2) noexcept { + return flags{f1.val_ ^ f2.val_}; + } + void swap(flags &fl) noexcept { std::swap(val_, fl.val_); } @@ -153,7 +173,7 @@ template struct flags { } - bool empty() const noexcept { return !val_; } + constexpr bool empty() const noexcept { return !val_; } size_type size() const noexcept { return std::distance(this->begin(), this->end()); @@ -165,13 +185,13 @@ template struct flags { iterator begin() const noexcept { return cbegin(); } iterator cbegin() const noexcept { return iterator{val_}; } - iterator end() const noexcept { return cend(); } - iterator cend() const noexcept { return {}; } + constexpr iterator end() const noexcept { return cend(); } + constexpr iterator cend() const noexcept { return {}; } - iterator find(enum_type e) const noexcept { return {val_, e}; } + constexpr iterator find(enum_type e) const noexcept { return {val_, e}; } - size_type count(enum_type e) const noexcept { + constexpr size_type count(enum_type e) const noexcept { return find(e) != end() ? 1 : 0; } @@ -256,67 +276,7 @@ template struct flags { template -constexpr flags operator|(flags f1, flags f2) noexcept { - return f1 |= f2; -} - -template -constexpr flags operator|(flags f, E e) noexcept { - return f |= e; -} - -template -constexpr flags operator|(E e, flags f) noexcept { - return f |= e; -} - - -template -constexpr flags operator&(flags f1, flags f2) noexcept { - return f1 &= f2; -} - -template -constexpr flags operator&(flags f, E e) noexcept { - return f &= e; -} - -template -constexpr flags operator&(E e, flags f) noexcept {; - return f &= e; -} - - -template -constexpr flags operator^(flags f1, flags f2) noexcept { - return f1 ^= f2; -} - -template -constexpr flags operator^(flags f, E e) noexcept { - return f ^= e; -} - -template -constexpr flags operator^(E e, flags f) noexcept { - return f ^= e; -} - - -template -constexpr bool operator==(const flags &fl1, const flags &fl2) noexcept { - return fl1.underlying_value() == fl2.underlying_value(); -} - - -template -constexpr bool operator!=(const flags &fl1, const flags &fl2) noexcept { - return fl1.underlying_value() != fl2.underlying_value(); -} - - -template -constexpr void swap(flags &fl1, flags &fl2) noexcept { fl1.swap(fl2); } +void swap(flags &fl1, flags &fl2) noexcept { fl1.swap(fl2); } } // namespace flags @@ -326,7 +286,7 @@ template constexpr auto operator|(E e1, E e2) noexcept -> typename std::enable_if::value, flags::flags>::type { - return flags::flags{e1} |= e2; + return flags::flags(e1) | e2; } @@ -334,7 +294,7 @@ template constexpr auto operator&(E e1, E e2) noexcept -> typename std::enable_if::value, flags::flags>::type { - return flags::flags{e1} &= e2; + return flags::flags(e1) & e2; } @@ -342,7 +302,7 @@ template constexpr auto operator^(E e1, E e2) noexcept -> typename std::enable_if::value, flags::flags>::type { - return flags::flags{e1} ^= e2; + return flags::flags(e1) ^ e2; } diff --git a/include/flags/iterator.hpp b/include/flags/iterator.hpp index 2d7063a05..b833c09f2 100644 --- a/include/flags/iterator.hpp +++ b/include/flags/iterator.hpp @@ -60,7 +60,7 @@ class FlagsIterator { using impl_type = typename flags_type::impl_type; - explicit FlagsIterator(impl_type uv) noexcept : mask_(1), uvalue_(uv) { + explicit FlagsIterator(impl_type uv) noexcept : uvalue_(uv), mask_(1) { if (!(mask_ & uvalue_)) { nextMask(); } } diff --git a/test/Jamroot b/test/Jamroot index 6e295f6fa..840cbf133 100644 --- a/test/Jamroot +++ b/test/Jamroot @@ -1,5 +1,6 @@ import testing ; + project flags_tests : requirements all -std=c++11 @@ -18,4 +19,12 @@ unit-test main-test : main-test.cpp boost_utf : BOOST_TEST_DYN_LINK BOOST_TEST_MODULE=enum_flags - ; \ No newline at end of file + ; + + +compile should-compile.cpp ; + + +for src in [ glob shouldnt-compile/*.cpp ] { + compile-fail $(src) ; +} diff --git a/test/common.hpp b/test/common.hpp new file mode 100644 index 000000000..34023e46a --- /dev/null +++ b/test/common.hpp @@ -0,0 +1,14 @@ +#ifndef ENUM_CLASS_TEST_COMMON_HPP +#define ENUM_CLASS_TEST_COMMON_HPP + + +#include + + +enum class Enum : int {One = 1, Two = 2, Four = 4, Eight = 8}; +ALLOW_FLAGS_FOR_ENUM(Enum) + +using Enums = flags::flags; + + +#endif // ENUM_CLASS_TEST_COMMON_HPP diff --git a/test/main-test.cpp b/test/main-test.cpp index bb376ac3b..b319b46ef 100644 --- a/test/main-test.cpp +++ b/test/main-test.cpp @@ -1,16 +1,10 @@ -#include +#include "common.hpp" #include #include -enum class Enum : int {One = 1, Two = 2, Four = 4, Eight = 8}; -ALLOW_FLAGS_FOR_ENUM(Enum) - -using Enums = flags::flags; - - BOOST_AUTO_TEST_CASE(set_underlying_value) { Enums result; constexpr int random_number = 87; diff --git a/test/should-compile.cpp b/test/should-compile.cpp new file mode 100644 index 000000000..649b06818 --- /dev/null +++ b/test/should-compile.cpp @@ -0,0 +1,147 @@ +#include "common.hpp" + + +// type traits +static_assert(std::is_pod::value, + "Enums is not POD!"); +static_assert(std::is_literal_type::value, + "Enums is not a literal type!"); + + +// associated types + +// general +static_assert(std::is_same::value, + "Enums::enum_type is not Enum!"); +static_assert(std::is_same::type, + Enums::underlying_type>::value, + "Enums::underlying_type is different from " + "underlying type of Enum!"); +static_assert(std::is_same::type, + Enums::impl_type>::value, + "Enums::impl_type is not unsigned version of " + "Enums::underlying_type!"); + +// iterator +using Iterator = Enums::iterator; + +static_assert(std::is_literal_type::value, + "Enums::iterator is not a literal type!"); +static_assert(std::is_same::value, + "Enums::const_iterator and Enums::iterator are different types!"); +static_assert(std::is_same::value, + "Enums::iterator::flags_type is not Enums!"); +static_assert(std::is_same::value, + "Enums::iterator category is not forward iterator!"); +static_assert(std::is_same::value, + "Enums::iterator::value_type is not Enum!"); +static_assert(std::is_same::value, + "Enums::iterator::reference is not const Enum!"); +// (const) forward iterator requirements +static_assert(std::is_copy_constructible::value + && std::is_copy_assignable::value + && std::is_destructible::value +// && std::is_same()), +// Iterator::reference>::value + && std::is_same()), + Iterator &>::value, + "Enums::iterator does not model Iterator!"); +static_assert(std::is_convertible< + decltype(std::declval() == std::declval()), + bool>::value, + "Enums::iterator does not model EqualityComparable!"); +static_assert(std::is_convertible< + decltype(std::declval() != std::declval()), + bool>::value + && std::is_convertible()), + Iterator::value_type>::value + && std::is_convertible()++), + Iterator::value_type>::value, + "Enums::iterator does not model InputIterator!"); +static_assert(std::is_default_constructible::value + && std::is_convertible()), + Iterator>::value + && std::is_convertible()++), + Iterator>::value, + "Enums::iterator does not model ForwardIterator!"); + +// container +static_assert(std::is_same::value, + "Enums::value_type is not Enums::iterator::value_type!"); + +static_assert(std::is_same::value, + "Enums::reference is not Enums::iterator::reference!"); +static_assert(std::is_same::value, + "Enums::const_reference is not Enums::reference!"); + +static_assert(std::is_same::value, + "Enums::pointer is not Enums::iterator::pointer!"); +static_assert(std::is_same::value, + "Enums::pointer is not Enum *!"); +static_assert(std::is_same::value, + "Enums::const_pointer is not const Enum *!"); + +static_assert(std::is_arithmetic::value, + "Enums::size_type is not arithmetic!"); + +static_assert(std::is_same::value, + "Enums::difference_type is not Enums::iterator::difference_type!" + ); +static_assert(std::is_signed::value, + "Enums::difference_type is not signed!"); + + +// constexpr construction +constexpr Enums ec1(flags::empty); +constexpr Enums ec2{flags::empty}; +constexpr Enums vc1(Enum::One); +constexpr auto vc2 = Enums(Enum::One); + + +// constexpr logical operators +constexpr bool l1 = static_cast(ec1); +constexpr bool l2 = !ec1; +constexpr bool l3 = ec1 == ec2; +constexpr bool l4 = ec1 != ec2; + + +// constexpr bitwise operators +constexpr auto b1 = ~ec1; + +constexpr auto b2 = ec1 | ec2; +constexpr auto b3 = ec1 | Enum::One; +constexpr auto b4 = Enum::One | ec1; +constexpr auto b5 = Enum::One | Enum::Two; + +constexpr auto b6 = ec1 & ec2; +constexpr auto b7 = ec1 & Enum::One; +constexpr auto b8 = Enum::One & ec1; +constexpr auto b9 = Enum::One & Enum::Two; + +constexpr auto b10 = ec1 ^ ec2; +constexpr auto b11 = ec1 & Enum::One; +constexpr auto b12 = Enum::One ^ ec1; +constexpr auto b13 = Enum::One ^ Enum::Two; + + +// constexpr conversions +constexpr auto cv1 = ec1.underlying_value(); +static_assert(std::is_same::value, + "Enums::underlying_value() did not return an object of type " + "Enums::underlying_type!"); +constexpr auto cv2 = ec1.to_bitset(); +constexpr auto cv3 = static_cast>(ec1); +static_assert(std::is_same::value, + "Bitset conversion functions return different types!"); + + +// constexpr container functions +constexpr bool cf1 = ec1.empty(); +constexpr Enums::size_type cf2 = ec1.max_size(); +constexpr Enums::iterator cf3 = ec1.find(Enum::One); +constexpr Enums::size_type cf4 = ec1.count(Enum::One); diff --git a/test/shouldnt-compile/allow-accidental.cpp b/test/shouldnt-compile/allow-accidental.cpp new file mode 100644 index 000000000..61827dea5 --- /dev/null +++ b/test/shouldnt-compile/allow-accidental.cpp @@ -0,0 +1,9 @@ +#include "common.hpp" + + +enum class AnotherEnum { One = 1, Two = 2 }; + + +void check() { + auto aes = AnotherEnum::One | AnotherEnum::Two; +} diff --git a/test/shouldnt-compile/common.hpp b/test/shouldnt-compile/common.hpp new file mode 100644 index 000000000..7d64c51a4 --- /dev/null +++ b/test/shouldnt-compile/common.hpp @@ -0,0 +1,18 @@ +#ifndef ENUM_CLASS_TEST_SHOULDNT_COMPILE_COMMON_HPP +#define ENUM_CLASS_TEST_SHOULDNT_COMPILE_COMMON_HPP + + +#include + + +enum class Enum { One = 1 }; +ALLOW_FLAGS_FOR_ENUM(Enum) +using Enums = flags::flags; + + +enum class OtherEnum { One = 1 }; +ALLOW_FLAGS_FOR_ENUM(OtherEnum) +using OtherEnums = flags::flags; + + +#endif // ENUM_CLASS_TEST_SHOULDNT_COMPILE_COMMON_HPP diff --git a/test/shouldnt-compile/const-clear.cpp b/test/shouldnt-compile/const-clear.cpp new file mode 100644 index 000000000..2f7705374 --- /dev/null +++ b/test/shouldnt-compile/const-clear.cpp @@ -0,0 +1,7 @@ +#include "common.hpp" + + +void check() { + const Enums es1; + es1.clear(); +} diff --git a/test/shouldnt-compile/const-enum-assign.cpp b/test/shouldnt-compile/const-enum-assign.cpp new file mode 100644 index 000000000..2c95d78f7 --- /dev/null +++ b/test/shouldnt-compile/const-enum-assign.cpp @@ -0,0 +1,7 @@ +#include "common.hpp" + + +void check() { + const Enums e; + e = Enum::One; +} diff --git a/test/shouldnt-compile/const-erase-iter.cpp b/test/shouldnt-compile/const-erase-iter.cpp new file mode 100644 index 000000000..f2aab1fdb --- /dev/null +++ b/test/shouldnt-compile/const-erase-iter.cpp @@ -0,0 +1,8 @@ +#include "common.hpp" + + +void check() { + const Enums es1; + Enum arr[] = {Enum::One}; + es1.erase(arr); +} diff --git a/test/shouldnt-compile/const-erase.cpp b/test/shouldnt-compile/const-erase.cpp new file mode 100644 index 000000000..74fe5dc8b --- /dev/null +++ b/test/shouldnt-compile/const-erase.cpp @@ -0,0 +1,7 @@ +#include "common.hpp" + + +void check() { + const Enums es1; + es1.erase(Enum::One); +} diff --git a/test/shouldnt-compile/const-il-assign.cpp b/test/shouldnt-compile/const-il-assign.cpp new file mode 100644 index 000000000..0a1da5b8c --- /dev/null +++ b/test/shouldnt-compile/const-il-assign.cpp @@ -0,0 +1,7 @@ +#include "common.hpp" + + +void check() { + const Enums e; + e = {Enum::One}; +} diff --git a/test/shouldnt-compile/const-insert-iter.cpp b/test/shouldnt-compile/const-insert-iter.cpp new file mode 100644 index 000000000..e1dfb9cd5 --- /dev/null +++ b/test/shouldnt-compile/const-insert-iter.cpp @@ -0,0 +1,8 @@ +#include "common.hpp" + + +void check() { + const Enums es1; + Enum arr[] = {Enum::One}; + es1.insert(arr, arr + 1); +} diff --git a/test/shouldnt-compile/const-insert.cpp b/test/shouldnt-compile/const-insert.cpp new file mode 100644 index 000000000..65ac65a54 --- /dev/null +++ b/test/shouldnt-compile/const-insert.cpp @@ -0,0 +1,7 @@ +#include "common.hpp" + + +void check() { + const Enums es1; + es1.insert(Enum::One); +} diff --git a/test/shouldnt-compile/const-set-uv.cpp b/test/shouldnt-compile/const-set-uv.cpp new file mode 100644 index 000000000..37540ee74 --- /dev/null +++ b/test/shouldnt-compile/const-set-uv.cpp @@ -0,0 +1,7 @@ +#include "common.hpp" + + +void check() { + const Enums es1; + es1.set_underlying_value(1); +} diff --git a/test/shouldnt-compile/const-swap.cpp b/test/shouldnt-compile/const-swap.cpp new file mode 100644 index 000000000..e9acb2aea --- /dev/null +++ b/test/shouldnt-compile/const-swap.cpp @@ -0,0 +1,8 @@ +#include "common.hpp" + + +void check() { + const Enums es1; + Enums es2; + es2.swap(es1); +} diff --git a/test/shouldnt-compile/implicit-bool-conv.cpp b/test/shouldnt-compile/implicit-bool-conv.cpp new file mode 100644 index 000000000..e9b23f2bd --- /dev/null +++ b/test/shouldnt-compile/implicit-bool-conv.cpp @@ -0,0 +1,10 @@ +#include "common.hpp" + + +void f(bool) {} + + +void check() { + Enums es; + f(es); +} diff --git a/test/shouldnt-compile/implicit-int-conv.cpp b/test/shouldnt-compile/implicit-int-conv.cpp new file mode 100644 index 000000000..e8d32cea7 --- /dev/null +++ b/test/shouldnt-compile/implicit-int-conv.cpp @@ -0,0 +1,10 @@ +#include "common.hpp" + + +void f(int) {} + + +void check() { + Enums es; + f(es); +} diff --git a/test/shouldnt-compile/int-conversion.cpp b/test/shouldnt-compile/int-conversion.cpp new file mode 100644 index 000000000..2b0f9e7c1 --- /dev/null +++ b/test/shouldnt-compile/int-conversion.cpp @@ -0,0 +1,6 @@ +#include "common.hpp" + + +void check() { + Enums es = Enums::underlying_type{1}; // conversion from an integer +} diff --git a/test/shouldnt-compile/iter-assign.cpp b/test/shouldnt-compile/iter-assign.cpp new file mode 100644 index 000000000..074d87e7f --- /dev/null +++ b/test/shouldnt-compile/iter-assign.cpp @@ -0,0 +1,8 @@ +#include "common.hpp" + + +void check() { + Enums e = Enum::One; + auto i = e.begin(); + *i = Enum::One; +} diff --git a/test/shouldnt-compile/not-allowed.cpp b/test/shouldnt-compile/not-allowed.cpp new file mode 100644 index 000000000..5bbf8e4d4 --- /dev/null +++ b/test/shouldnt-compile/not-allowed.cpp @@ -0,0 +1,10 @@ +#include + + +enum class SomeEnum { One = 1 }; +using SomeEnums = flags::flags; // no falgs::is_flags<> specialization + // for SomeEnum + +void check() { + SomeEnums se; +} diff --git a/test/shouldnt-compile/wrong-enum.cpp b/test/shouldnt-compile/wrong-enum.cpp new file mode 100644 index 000000000..cfe8ea14e --- /dev/null +++ b/test/shouldnt-compile/wrong-enum.cpp @@ -0,0 +1,6 @@ +#include "common.hpp" + + +void check() { + Enums e = OtherEnum::One; +} diff --git a/test/shouldnt-compile/wrong-flags.cpp b/test/shouldnt-compile/wrong-flags.cpp new file mode 100644 index 000000000..616a436fe --- /dev/null +++ b/test/shouldnt-compile/wrong-flags.cpp @@ -0,0 +1,6 @@ +#include "common.hpp" + + +void check() { + Enums e = OtherEnums{OtherEnum::One}; +} diff --git a/test/shouldnt-compile/wrong-iter.cpp b/test/shouldnt-compile/wrong-iter.cpp new file mode 100644 index 000000000..2f4a919ef --- /dev/null +++ b/test/shouldnt-compile/wrong-iter.cpp @@ -0,0 +1,11 @@ +#include "common.hpp" + +#include + + +void check() { + Enums es = Enum::One; + auto beg = std::begin(es), end = std::end(es); + + OtherEnums oes{beg, end}; +} diff --git a/test/shouldnt-compile/wrong-variadic.cpp b/test/shouldnt-compile/wrong-variadic.cpp new file mode 100644 index 000000000..8207b01de --- /dev/null +++ b/test/shouldnt-compile/wrong-variadic.cpp @@ -0,0 +1,6 @@ +#include "common.hpp" + + +void check() { + Enums e(Enum::One, 1); +} From 58ecac61fbad435fc82e845dd10ca1429ac36a28 Mon Sep 17 00:00:00 2001 From: Dmitry Arkhipov Date: Sun, 7 Jun 2015 06:57:26 +0300 Subject: [PATCH 3/3] slightly updated readme --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 42195b9bb..7e7a92abf 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,9 @@ if (mask1 & Value2) { // if Value2 flag is set ``` ## Description + +**Disclaimer: docs are currently out of sync a little bit** + ``` c++ template class flags; ``` @@ -56,7 +59,8 @@ underlying_type|The integer type that is used as representation of `flags`|Equiv #### Constructors and assignment operators Name |Description -----------------------------|----------- -`flags()` |Default contructor (all flags are unset) +`flags()` |Default contructor, keeps object uninitialized (note: object may contain garbage) +`flags(empty_t)` |Unsets all flags `flags(flags::enum_type)` |Sets flag denoted by the parameter `flags(const flags&)` |Copy constructor `flags(flags&&)` |Move constructor