Skip to content

Commit e88e44c

Browse files
committed
comparison functions are now constexpr (fixes #52)
1 parent f28952c commit e88e44c

5 files changed

Lines changed: 98 additions & 21 deletions

File tree

include/boost/pfr/detail/functional.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ namespace boost { namespace pfr { namespace detail {
158158
}
159159

160160
template <template <std::size_t, std::size_t> class Visitor, class T, class U>
161-
bool binary_visit(const T& x, const U& y) {
161+
constexpr bool binary_visit(const T& x, const U& y) {
162162
constexpr std::size_t fields_count_lhs = detail::fields_count<std::remove_reference_t<T>>();
163163
constexpr std::size_t fields_count_rhs = detail::fields_count<std::remove_reference_t<U>>();
164164
constexpr std::size_t fields_count_min = detail::min_size(fields_count_lhs, fields_count_rhs);

include/boost/pfr/ops.hpp

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,13 @@ namespace detail {
8282
///
8383
/// \returns true if lhs is equal to rhs; false otherwise
8484
template <class T, class U>
85-
detail::enable_not_eq_comp_t<T, U> eq(const T& lhs, const U& rhs) noexcept {
85+
constexpr detail::enable_not_eq_comp_t<T, U> eq(const T& lhs, const U& rhs) noexcept {
8686
return boost::pfr::eq_fields(lhs, rhs);
8787
}
8888

8989
/// \overload eq
9090
template <class T, class U>
91-
detail::enable_eq_comp_t<T, U> eq(const T& lhs, const U& rhs) {
91+
constexpr detail::enable_eq_comp_t<T, U> eq(const T& lhs, const U& rhs) {
9292
return lhs == rhs;
9393
}
9494

@@ -97,13 +97,13 @@ detail::enable_eq_comp_t<T, U> eq(const T& lhs, const U& rhs) {
9797
///
9898
/// \returns true if lhs is not equal to rhs; false otherwise
9999
template <class T, class U>
100-
detail::enable_not_ne_comp_t<T, U> ne(const T& lhs, const U& rhs) noexcept {
100+
constexpr detail::enable_not_ne_comp_t<T, U> ne(const T& lhs, const U& rhs) noexcept {
101101
return boost::pfr::ne_fields(lhs, rhs);
102102
}
103103

104104
/// \overload ne
105105
template <class T, class U>
106-
detail::enable_ne_comp_t<T, U> ne(const T& lhs, const U& rhs) {
106+
constexpr detail::enable_ne_comp_t<T, U> ne(const T& lhs, const U& rhs) {
107107
return lhs != rhs;
108108
}
109109

@@ -112,13 +112,13 @@ detail::enable_ne_comp_t<T, U> ne(const T& lhs, const U& rhs) {
112112
///
113113
/// \returns true if lhs is less than rhs; false otherwise
114114
template <class T, class U>
115-
detail::enable_not_lt_comp_t<T, U> lt(const T& lhs, const U& rhs) noexcept {
115+
constexpr detail::enable_not_lt_comp_t<T, U> lt(const T& lhs, const U& rhs) noexcept {
116116
return boost::pfr::lt_fields(lhs, rhs);
117117
}
118118

119119
/// \overload lt
120120
template <class T, class U>
121-
detail::enable_lt_comp_t<T, U> lt(const T& lhs, const U& rhs) {
121+
constexpr detail::enable_lt_comp_t<T, U> lt(const T& lhs, const U& rhs) {
122122
return lhs < rhs;
123123
}
124124

@@ -127,13 +127,13 @@ detail::enable_lt_comp_t<T, U> lt(const T& lhs, const U& rhs) {
127127
///
128128
/// \returns true if lhs is greater than rhs; false otherwise
129129
template <class T, class U>
130-
detail::enable_not_gt_comp_t<T, U> gt(const T& lhs, const U& rhs) noexcept {
130+
constexpr detail::enable_not_gt_comp_t<T, U> gt(const T& lhs, const U& rhs) noexcept {
131131
return boost::pfr::gt_fields(lhs, rhs);
132132
}
133133

134134
/// \overload gt
135135
template <class T, class U>
136-
detail::enable_gt_comp_t<T, U> gt(const T& lhs, const U& rhs) {
136+
constexpr detail::enable_gt_comp_t<T, U> gt(const T& lhs, const U& rhs) {
137137
return lhs > rhs;
138138
}
139139

@@ -142,13 +142,13 @@ detail::enable_gt_comp_t<T, U> gt(const T& lhs, const U& rhs) {
142142
///
143143
/// \returns true if lhs is less or equal to rhs; false otherwise
144144
template <class T, class U>
145-
detail::enable_not_le_comp_t<T, U> le(const T& lhs, const U& rhs) noexcept {
145+
constexpr detail::enable_not_le_comp_t<T, U> le(const T& lhs, const U& rhs) noexcept {
146146
return boost::pfr::le_fields(lhs, rhs);
147147
}
148148

149149
/// \overload le
150150
template <class T, class U>
151-
detail::enable_le_comp_t<T, U> le(const T& lhs, const U& rhs) {
151+
constexpr detail::enable_le_comp_t<T, U> le(const T& lhs, const U& rhs) {
152152
return lhs <= rhs;
153153
}
154154

@@ -157,13 +157,13 @@ detail::enable_le_comp_t<T, U> le(const T& lhs, const U& rhs) {
157157
///
158158
/// \returns true if lhs is greater or equal to rhs; false otherwise
159159
template <class T, class U>
160-
detail::enable_not_ge_comp_t<T, U> ge(const T& lhs, const U& rhs) noexcept {
160+
constexpr detail::enable_not_ge_comp_t<T, U> ge(const T& lhs, const U& rhs) noexcept {
161161
return boost::pfr::ge_fields(lhs, rhs);
162162
}
163163

164164
/// \overload ge
165165
template <class T, class U>
166-
detail::enable_ge_comp_t<T, U> ge(const T& lhs, const U& rhs) {
166+
constexpr detail::enable_ge_comp_t<T, U> ge(const T& lhs, const U& rhs) {
167167
return lhs >= rhs;
168168
}
169169

@@ -172,13 +172,13 @@ detail::enable_ge_comp_t<T, U> ge(const T& lhs, const U& rhs) {
172172
///
173173
/// \returns std::size_t with hash of the value
174174
template <class T>
175-
detail::enable_not_hashable_t<T> hash_value(const T& value) noexcept {
175+
constexpr detail::enable_not_hashable_t<T> hash_value(const T& value) noexcept {
176176
return boost::pfr::hash_fields(value);
177177
}
178178

179179
/// \overload hash_value
180180
template <class T>
181-
detail::enable_hashable_t<T> hash_value(const T& value) {
181+
constexpr detail::enable_hashable_t<T> hash_value(const T& value) {
182182
return std::hash<T>{}(value);
183183
}
184184

include/boost/pfr/ops_fields.hpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ namespace boost { namespace pfr {
3939
/// `R` are the results of calling `std::tie` on first `N` fields of `lhs` and
4040
// `rhs` respectively; `N` is `std::min(tuple_size_v<T>, tuple_size_v<U>)`.
4141
template <class T, class U>
42-
bool eq_fields(const T& lhs, const U& rhs) noexcept {
42+
constexpr bool eq_fields(const T& lhs, const U& rhs) noexcept {
4343
return detail::binary_visit<detail::equal_impl>(lhs, rhs);
4444
}
4545

@@ -50,7 +50,7 @@ namespace boost { namespace pfr {
5050
/// `R` are the results of calling `std::tie` on first `N` fields of `lhs` and
5151
// `rhs` respectively; `N` is `std::min(tuple_size_v<T>, tuple_size_v<U>)`.
5252
template <class T, class U>
53-
bool ne_fields(const T& lhs, const U& rhs) noexcept {
53+
constexpr bool ne_fields(const T& lhs, const U& rhs) noexcept {
5454
return detail::binary_visit<detail::not_equal_impl>(lhs, rhs);
5555
}
5656

@@ -60,7 +60,7 @@ namespace boost { namespace pfr {
6060
/// `R` are the results of calling `std::tie` on first `N` fields of `lhs` and
6161
// `rhs` respectively; `N` is `std::min(tuple_size_v<T>, tuple_size_v<U>)`.
6262
template <class T, class U>
63-
bool gt_fields(const T& lhs, const U& rhs) noexcept {
63+
constexpr bool gt_fields(const T& lhs, const U& rhs) noexcept {
6464
return detail::binary_visit<detail::greater_impl>(lhs, rhs);
6565
}
6666

@@ -71,7 +71,7 @@ namespace boost { namespace pfr {
7171
/// `R` are the results of calling `std::tie` on first `N` fields of `lhs` and
7272
// `rhs` respectively; `N` is `std::min(tuple_size_v<T>, tuple_size_v<U>)`.
7373
template <class T, class U>
74-
bool lt_fields(const T& lhs, const U& rhs) noexcept {
74+
constexpr bool lt_fields(const T& lhs, const U& rhs) noexcept {
7575
return detail::binary_visit<detail::less_impl>(lhs, rhs);
7676
}
7777

@@ -82,7 +82,7 @@ namespace boost { namespace pfr {
8282
/// `R` are the results of calling `std::tie` on first `N` fields of `lhs` and
8383
// `rhs` respectively; `N` is `std::min(tuple_size_v<T>, tuple_size_v<U>)`.
8484
template <class T, class U>
85-
bool ge_fields(const T& lhs, const U& rhs) noexcept {
85+
constexpr bool ge_fields(const T& lhs, const U& rhs) noexcept {
8686
return detail::binary_visit<detail::greater_equal_impl>(lhs, rhs);
8787
}
8888

@@ -93,7 +93,7 @@ namespace boost { namespace pfr {
9393
/// `R` are the results of calling `std::tie` on first `N` fields of `lhs` and
9494
// `rhs` respectively; `N` is `std::min(tuple_size_v<T>, tuple_size_v<U>)`.
9595
template <class T, class U>
96-
bool le_fields(const T& lhs, const U& rhs) noexcept {
96+
constexpr bool le_fields(const T& lhs, const U& rhs) noexcept {
9797
return detail::binary_visit<detail::less_equal_impl>(lhs, rhs);
9898
}
9999

test/Jamfile.v2

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ test-suite pfr_tests
6767
;
6868

6969
local BLACKLIST_TESTS_FOR_LOOPHOLE =
70+
constexpr_ops # Loophole is not constexpr usable because of the reinterpret_cast usage
7071
get_const_field # boost::pfr::get gives compile time error on const fields
7172
optional_chrono # boost::pfr::* has problems with std::optional, produces compile time error
7273
template_constructor # Template constructor in one of the fields of the aggregate
@@ -77,6 +78,7 @@ local BLACKLIST_TESTS_FOR_LOOPHOLE =
7778
# * reflecting a non literal type
7879
# * or calling boost::pfr::get and the result is a user defined structure
7980
local BLACKLIST_TESTS_FOR_CLASSIC =
81+
constexpr_ops
8082
get_const_field
8183
get_non_default_constructible
8284
get_rvalue

test/run/constexpr_ops.cpp

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// Copyright (c) 2016-2020 Antony Polukhin
2+
//
3+
// Distributed under the Boost Software License, Version 1.0. (See accompanying
4+
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5+
6+
#include <boost/pfr/ops.hpp>
7+
#include <boost/pfr/io.hpp>
8+
9+
#include <iostream>
10+
#include <typeinfo>
11+
#include <tuple>
12+
#include <sstream>
13+
#include <set>
14+
#include <string>
15+
16+
#include <boost/core/lightweight_test.hpp>
17+
18+
#ifdef __clang__
19+
# pragma clang diagnostic ignored "-Wmissing-braces"
20+
#endif
21+
22+
union test_union {
23+
int i;
24+
float f;
25+
};
26+
27+
constexpr bool operator< (test_union l, test_union r) noexcept { return l.i < r.i; }
28+
constexpr bool operator<=(test_union l, test_union r) noexcept { return l.i <= r.i; }
29+
constexpr bool operator> (test_union l, test_union r) noexcept { return l.i > r.i; }
30+
constexpr bool operator>=(test_union l, test_union r) noexcept { return l.i >= r.i; }
31+
constexpr bool operator==(test_union l, test_union r) noexcept { return l.i == r.i; }
32+
constexpr bool operator!=(test_union l, test_union r) noexcept { return l.i != r.i; }
33+
34+
35+
template <class T>
36+
void test_constexpr_comparable() {
37+
using namespace boost::pfr;
38+
constexpr T s1 {110, 1, true, 6,17,8,9,10,11};
39+
constexpr T s2 = s1;
40+
constexpr T s3 {110, 1, true, 6,17,8,9,10,11111};
41+
static_assert(eq(s1, s2), "");
42+
static_assert(le(s1, s2), "");
43+
static_assert(ge(s1, s2), "");
44+
static_assert(!ne(s1, s2), "");
45+
static_assert(!eq(s1, s3), "");
46+
static_assert(ne(s1, s3), "");
47+
static_assert(lt(s1, s3), "");
48+
static_assert(gt(s3, s2), "");
49+
static_assert(le(s1, s3), "");
50+
static_assert(ge(s3, s2), "");
51+
}
52+
53+
namespace foo {
54+
struct comparable_struct {
55+
int i; short s; bool bl; int a,b,c,d,e,f;
56+
};
57+
}
58+
59+
int main() {
60+
test_constexpr_comparable<foo::comparable_struct>();
61+
62+
struct local_comparable_struct {
63+
int i; short s; bool bl; int a,b,c,d,e,f;
64+
};
65+
test_constexpr_comparable<local_comparable_struct>();
66+
67+
struct local_comparable_struct_with_union {
68+
int i; short s; bool bl; int a,b,c,d,e; test_union u;
69+
};
70+
test_constexpr_comparable<local_comparable_struct>();
71+
72+
return boost::report_errors();
73+
}
74+
75+

0 commit comments

Comments
 (0)