Skip to content

Commit b589f5d

Browse files
committed
Enable declaring constexpr funcs/vars with ==, improve enum/flag_enum
Simplifying `enum` and `flag_enum` needed: - evolving the `==` compile-time alias design to be the way we we express compile-time `constexpr` functions and objects - including to work around Cpp1's limitation on declaring `constexpr`/`inline`/`static` members of a type that have an incomplete type, including the same type being defined, by using the dance described in https://stackoverflow.com/questions/11928089/ - enabling emitting `operator<<` as a `friend` function
1 parent ba843af commit b589f5d

16 files changed

+581
-497
lines changed

Diff for: include/cpp2util.h

+9-48
Original file line numberDiff line numberDiff line change
@@ -1586,59 +1586,20 @@ constexpr auto unsafe_narrow( X&& x ) noexcept -> decltype(auto)
15861586

15871587
//-----------------------------------------------------------------------
15881588
//
1589-
// strict_value: a strong typedef-like helper for value types
1589+
// has_flags: query whether a flag_enum value has all flags in 'flags' set
15901590
//
1591-
// Intended for use as an underlying type for types/variables where you
1592-
// don't want implicit conversions or comparisons to happen between
1593-
// values even if they may share the same underlying type (e.g.,
1594-
// Color::Red and CardGame::Poker may both be represented as an `int`
1595-
// but shouldn't be interconvertible or intercomparable)
1596-
//
1597-
// Used by the `enum` and `flag_enum` metafunctions
1591+
// flags set of flags to check
15981592
//
1593+
// Returns a function object that takes a 'value' of the same type as
1594+
// 'flags', and evaluates to true if and only if 'value' has set all of
1595+
// the bits set in 'flags'
1596+
//
15991597
//-----------------------------------------------------------------------
16001598
//
1601-
template <typename T, typename Tag, bool BitwiseOps>
1602-
class strict_value {
1603-
T t = {};
1604-
public:
1605-
explicit constexpr strict_value() { }
1606-
1607-
template <typename U>
1608-
explicit constexpr strict_value(U const& u) : t{unsafe_narrow<T>(u)} { }
1609-
1610-
template <typename U> requires std::is_convertible_v<T,U>
1611-
explicit constexpr operator U() const { return t; }
1612-
1613-
template <typename U> requires std::is_convertible_v<T,U>
1614-
explicit constexpr operator U() { return t; }
1615-
1616-
constexpr auto operator<=>( strict_value const& ) const -> std::strong_ordering = default;
1617-
1618-
auto to_string() const -> std::string { return Tag::to_string(*this); }
1619-
1620-
friend auto operator<<(std::ostream& o, strict_value const& v) -> std::ostream& { return o << v.to_string(); }
1621-
1622-
// Bitwise operations
1623-
1624-
constexpr auto operator|=( strict_value const& that ) -> strict_value requires BitwiseOps { t |= that.t; return *this; }
1625-
constexpr auto operator&=( strict_value const& that ) -> strict_value requires BitwiseOps { t &= that.t; return *this; }
1626-
constexpr auto operator^=( strict_value const& that ) -> strict_value requires BitwiseOps { t ^= that.t; return *this; }
1627-
1628-
constexpr auto operator| ( strict_value const& that ) const -> strict_value requires BitwiseOps { return strict_value(t | that.t); }
1629-
constexpr auto operator& ( strict_value const& that ) const -> strict_value requires BitwiseOps { return strict_value(t & that.t); }
1630-
constexpr auto operator^ ( strict_value const& that ) const -> strict_value requires BitwiseOps { return strict_value(t ^ that.t); }
1631-
1632-
constexpr auto has ( strict_value const& that ) const -> bool requires BitwiseOps { return t & that.t; }
1633-
1634-
constexpr auto set ( strict_value const& that ) -> void requires BitwiseOps { t |= that.t; }
1635-
constexpr auto clear ( strict_value const& that ) -> void requires BitwiseOps { t &= ~that.t; }
1636-
};
1637-
1638-
template <typename T, typename Tag>
1639-
auto has_flags(strict_value<T, Tag, true> flags)
1599+
template <typename T>
1600+
auto has_flags(T flags)
16401601
{
1641-
return [=](strict_value<T, Tag, true> value) { return (value & flags) == flags; };
1602+
return [=](T value) { return (value & flags) == flags; };
16421603
}
16431604

16441605

Diff for: regression-tests/pure2-enum.cpp2

+13-6
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,17 @@ main: () = {
6565

6666
x = skat_game::diamonds; // ok, can assign one skat_game from another
6767

68+
std::cout << "file_attributes::cached.get_raw_value() is (file_attributes::cached.get_raw_value())$\n";
69+
std::cout << "file_attributes::current.get_raw_value() is (file_attributes::current.get_raw_value())$\n";
70+
std::cout << "file_attributes::obsolete.get_raw_value() is (file_attributes::obsolete.get_raw_value())$\n";
71+
std::cout << "file_attributes::cached_and_current.get_raw_value() is (file_attributes::cached_and_current.get_raw_value())$\n";
72+
6873
f: file_attributes = file_attributes::cached_and_current;
69-
f &= file_attributes::cached | file_attributes::obsolete;
74+
f &= file_attributes::cached | file_attributes::obsolete;
75+
std::cout << "f. get_raw_value() is (f. get_raw_value())$\n";
7076

7177
f2 := file_attributes::cached;
78+
std::cout << "f2.get_raw_value() is (f2.get_raw_value())$\n";
7279

7380
std::cout << "f is " << f << "\n";
7481
std::cout << "f2 is " << f2 << "\n";
@@ -78,8 +85,8 @@ main: () = {
7885
f2.set(file_attributes::cached);
7986
std::cout << "f2 is " << f2 << "\n";
8087

81-
std::cout << "f as int is (f as int )$\n";
82-
std::cout << "f2 as int is (f2 as int )$\n";
88+
std::cout << "f. get_raw_value() is (f. get_raw_value())$\n";
89+
std::cout << "f2.get_raw_value() is (f2.get_raw_value())$\n";
8390

8491
std::cout << "f is (f2) is (f is (f2))$\n";
8592
std::cout << "f2 is (f ) is (f2 is (f ))$\n\n";
@@ -91,14 +98,14 @@ main: () = {
9198

9299
std::cout << "f is " << f << "\n";
93100
std::cout << "f2 is " << f2 << "\n";
94-
std::cout << "f as int is (f as int )$\n";
95-
std::cout << "f2 as int is (f2 as int )$\n";
101+
std::cout << "f. get_raw_value() is (f. get_raw_value())$\n";
102+
std::cout << "f2.get_raw_value() is (f2.get_raw_value())$\n";
96103
std::cout << "f == f2 is (f == f2 )$\n";
97104
std::cout << "f is (f2) is (f is (f2))$\n";
98105
std::cout << "f2 is (f ) is (f2 is (f ))$\n";
99106
std::cout << "(f & f2) == f2 is ((f & f2) == f2)$\n";
100107

101-
std::cout << "inspecting: " << inspect f -> std::string {
108+
std::cout << "inspecting f: " << inspect f -> std::string {
102109
is (file_attributes::current) = "exactly 'current'";
103110
is (cpp2::has_flags(f2)) = "includes all f2's flags ('cached' and 'current')";
104111
is _ = "something else";

Diff for: regression-tests/test-results/clang-12/pure2-enum.cpp.execution

+11-5
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,27 @@ using << prints clubs
44
with if else: clubs
55
with inspect: clubs
66

7+
file_attributes::cached.get_raw_value() is 1
8+
file_attributes::current.get_raw_value() is 2
9+
file_attributes::obsolete.get_raw_value() is 4
10+
file_attributes::cached_and_current.get_raw_value() is 3
11+
f. get_raw_value() is 1
12+
f2.get_raw_value() is 1
713
f is (cached)
814
f2 is (cached)
915
f2 is (none)
1016
f2 is (cached)
11-
f as int is 1
12-
f2 as int is 1
17+
f. get_raw_value() is 1
18+
f2.get_raw_value() is 1
1319
f is (f2) is true
1420
f2 is (f ) is true
1521

1622
f is (cached, current, obsolete, cached_and_current)
1723
f2 is (cached, current, cached_and_current)
18-
f as int is 7
19-
f2 as int is 3
24+
f. get_raw_value() is 7
25+
f2.get_raw_value() is 3
2026
f == f2 is false
2127
f is (f2) is false
2228
f2 is (f ) is false
2329
(f & f2) == f2 is true
24-
inspecting: includes all f2's flags ('cached' and 'current')
30+
inspecting f: includes all f2's flags ('cached' and 'current')

Diff for: regression-tests/test-results/gcc-10/pure2-enum.cpp.execution

+11-5
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,27 @@ using << prints clubs
44
with if else: clubs
55
with inspect: clubs
66

7+
file_attributes::cached.get_raw_value() is 1
8+
file_attributes::current.get_raw_value() is 2
9+
file_attributes::obsolete.get_raw_value() is 4
10+
file_attributes::cached_and_current.get_raw_value() is 3
11+
f. get_raw_value() is 1
12+
f2.get_raw_value() is 1
713
f is (cached)
814
f2 is (cached)
915
f2 is (none)
1016
f2 is (cached)
11-
f as int is 1
12-
f2 as int is 1
17+
f. get_raw_value() is 1
18+
f2.get_raw_value() is 1
1319
f is (f2) is true
1420
f2 is (f ) is true
1521

1622
f is (cached, current, obsolete, cached_and_current)
1723
f2 is (cached, current, cached_and_current)
18-
f as int is 7
19-
f2 as int is 3
24+
f. get_raw_value() is 7
25+
f2.get_raw_value() is 3
2026
f == f2 is false
2127
f is (f2) is false
2228
f2 is (f ) is false
2329
(f & f2) == f2 is true
24-
inspecting: includes all f2's flags ('cached' and 'current')
30+
inspecting f: includes all f2's flags ('cached' and 'current')

Diff for: regression-tests/test-results/gcc-10/pure2-print.cpp.output

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ In file included from pure2-print.cpp:7:
33
pure2-print.cpp2:7:1: note: in expansion of macro ‘CPP2_REQUIRES_’
44
../../../include/cpp2util.h:10005:33: error: expected initializer before ‘static_assert’
55
pure2-print.cpp2:89:1: note: in expansion of macro ‘CPP2_REQUIRES_’
6+
pure2-print.cpp2:6:24: error: ‘constexpr const T outer::object_alias’ is not a static data member of ‘class outer’
7+
pure2-print.cpp2:6:31: error: template definition of non-template ‘constexpr const T outer::object_alias’
68
pure2-print.cpp2:88:37: error: no declaration matches ‘void outer::print(std::ostream&, const Args& ...) requires cpp2::cmp_greater_eq(sizeof (Args)..., 0)’
79
pure2-print.cpp2:88:37: note: no functions named ‘void outer::print(std::ostream&, const Args& ...) requires cpp2::cmp_greater_eq(sizeof (Args)..., 0)’
810
pure2-print.cpp2:4:7: note: ‘class outer’ defined here

Diff for: regression-tests/test-results/gcc-13/pure2-enum.cpp.execution

+11-5
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,27 @@ using << prints clubs
44
with if else: clubs
55
with inspect: clubs
66

7+
file_attributes::cached.get_raw_value() is 1
8+
file_attributes::current.get_raw_value() is 2
9+
file_attributes::obsolete.get_raw_value() is 4
10+
file_attributes::cached_and_current.get_raw_value() is 3
11+
f. get_raw_value() is 1
12+
f2.get_raw_value() is 1
713
f is (cached)
814
f2 is (cached)
915
f2 is (none)
1016
f2 is (cached)
11-
f as int is 1
12-
f2 as int is 1
17+
f. get_raw_value() is 1
18+
f2.get_raw_value() is 1
1319
f is (f2) is true
1420
f2 is (f ) is true
1521

1622
f is (cached, current, obsolete, cached_and_current)
1723
f2 is (cached, current, cached_and_current)
18-
f as int is 7
19-
f2 as int is 3
24+
f. get_raw_value() is 7
25+
f2.get_raw_value() is 3
2026
f == f2 is false
2127
f is (f2) is false
2228
f2 is (f ) is false
2329
(f & f2) == f2 is true
24-
inspecting: includes all f2's flags ('cached' and 'current')
30+
inspecting f: includes all f2's flags ('cached' and 'current')

Diff for: regression-tests/test-results/msvc-2022/pure2-enum.cpp.execution

+11-5
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,27 @@ using << prints clubs
44
with if else: clubs
55
with inspect: clubs
66

7+
file_attributes::cached.get_raw_value() is 1
8+
file_attributes::current.get_raw_value() is 2
9+
file_attributes::obsolete.get_raw_value() is 4
10+
file_attributes::cached_and_current.get_raw_value() is 3
11+
f. get_raw_value() is 1
12+
f2.get_raw_value() is 1
713
f is (cached)
814
f2 is (cached)
915
f2 is (none)
1016
f2 is (cached)
11-
f as int is 1
12-
f2 as int is 1
17+
f. get_raw_value() is 1
18+
f2.get_raw_value() is 1
1319
f is (f2) is true
1420
f2 is (f ) is true
1521

1622
f is (cached, current, obsolete, cached_and_current)
1723
f2 is (cached, current, cached_and_current)
18-
f as int is 7
19-
f2 as int is 3
24+
f. get_raw_value() is 7
25+
f2.get_raw_value() is 3
2026
f == f2 is false
2127
f is (f2) is false
2228
f2 is (f ) is false
2329
(f & f2) == f2 is true
24-
inspecting: includes all f2's flags ('cached' and 'current')
30+
inspecting f: includes all f2's flags ('cached' and 'current')

Diff for: regression-tests/test-results/pure2-bugfix-for-max-munch.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
//=== Cpp2 type definitions and function declarations ===========================
1212

13-
template<typename T> auto static constexpr v = 0;
13+
template<typename T> auto inline constexpr v = 0;
1414
auto main() -> int;
1515

1616

0 commit comments

Comments
 (0)