Skip to content

Commit a529e78

Browse files
committed
Adedd static_assert messages for modifier mismatch with underlying type
1 parent 339526d commit a529e78

19 files changed

+246
-108
lines changed

ChangeLog

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
* Added static_assert() messages explaining why a modifier cannot be
2+
used with an underlying type. Thank you SilmaliTech for suggesting
3+
the improvement.
4+
15
* Added modifier `invocable` for types with operator(). Thank you
26
Dominic Koepke for the suggestion and the draft implementation.
37

include/strong_type/arithmetic.hpp

Lines changed: 44 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -21,30 +21,35 @@
2121
namespace strong
2222
{
2323
struct arithmetic {
24-
template<typename T>
25-
class modifier;
24+
template<typename T, typename = void>
25+
class modifier
26+
{
27+
static_assert(impl::always_false<T>,
28+
"Underlying type must support arithmeric operations");
29+
};
2630
};
2731

28-
template <typename T>
29-
class arithmetic::modifier
32+
template <typename T, typename Tag, typename ... Ms>
33+
class arithmetic::modifier<strong::type<T, Tag, Ms...>, impl::void_t<decltype(std::declval<T>() * std::declval<T>() - std::declval<T>() / std::declval<T>())>>
3034
{
35+
using type = strong::type<T, Tag, Ms...>;
3136
public:
3237
STRONG_NODISCARD
3338
friend
3439
STRONG_CONSTEXPR
35-
T
40+
type
3641
operator-(
37-
const T &lh)
42+
const type &lh)
3843
{
39-
return T{-value_of(lh)};
44+
return type{-value_of(lh)};
4045
}
4146

4247
friend
4348
STRONG_CONSTEXPR
44-
T&
49+
type&
4550
operator+=(
46-
T &lh,
47-
const T &rh)
51+
type &lh,
52+
const type &rh)
4853
noexcept(noexcept(value_of(lh) += value_of(rh)))
4954
{
5055
value_of(lh) += value_of(rh);
@@ -53,10 +58,10 @@ class arithmetic::modifier
5358

5459
friend
5560
STRONG_CONSTEXPR
56-
T&
61+
type&
5762
operator-=(
58-
T &lh,
59-
const T &rh)
63+
type &lh,
64+
const type &rh)
6065
noexcept(noexcept(value_of(lh) -= value_of(rh)))
6166
{
6267
value_of(lh) -= value_of(rh);
@@ -65,10 +70,10 @@ class arithmetic::modifier
6570

6671
friend
6772
STRONG_CONSTEXPR
68-
T&
73+
type&
6974
operator*=(
70-
T &lh,
71-
const T &rh)
75+
type &lh,
76+
const type &rh)
7277
noexcept(noexcept(value_of(lh) *= value_of(rh)))
7378
{
7479
value_of(lh) *= value_of(rh);
@@ -77,23 +82,23 @@ class arithmetic::modifier
7782

7883
friend
7984
STRONG_CONSTEXPR
80-
T&
85+
type&
8186
operator/=(
82-
T &lh,
83-
const T &rh)
87+
type &lh,
88+
const type &rh)
8489
noexcept(noexcept(value_of(lh) /= value_of(rh)))
8590
{
8691
value_of(lh) /= value_of(rh);
8792
return lh;
8893
}
8994

90-
template <typename TT = T, typename = decltype(value_of(std::declval<TT>()) % value_of(std::declval<TT>()))>
95+
template <typename TT = T, typename = decltype(std::declval<TT>() % std::declval<TT>())>
9196
friend
9297
STRONG_CONSTEXPR
93-
T&
98+
type&
9499
operator%=(
95-
T &lh,
96-
const T &rh)
100+
type &lh,
101+
const type &rh)
97102
noexcept(noexcept(value_of(lh) %= value_of(rh)))
98103
{
99104
value_of(lh) %= value_of(rh);
@@ -103,10 +108,10 @@ class arithmetic::modifier
103108
STRONG_NODISCARD
104109
friend
105110
STRONG_CONSTEXPR
106-
T
111+
type
107112
operator+(
108-
T lh,
109-
const T &rh)
113+
type lh,
114+
const type &rh)
110115
{
111116
lh += rh;
112117
return lh;
@@ -115,10 +120,10 @@ class arithmetic::modifier
115120
STRONG_NODISCARD
116121
friend
117122
STRONG_CONSTEXPR
118-
T
123+
type
119124
operator-(
120-
T lh,
121-
const T &rh)
125+
type lh,
126+
const type &rh)
122127
{
123128
lh -= rh;
124129
return lh;
@@ -127,10 +132,10 @@ class arithmetic::modifier
127132
STRONG_NODISCARD
128133
friend
129134
STRONG_CONSTEXPR
130-
T
135+
type
131136
operator*(
132-
T lh,
133-
const T &rh)
137+
type lh,
138+
const type &rh)
134139
{
135140
lh *= rh;
136141
return lh;
@@ -139,23 +144,23 @@ class arithmetic::modifier
139144
STRONG_NODISCARD
140145
friend
141146
STRONG_CONSTEXPR
142-
T
147+
type
143148
operator/(
144-
T lh,
145-
const T &rh)
149+
type lh,
150+
const type &rh)
146151
{
147152
lh /= rh;
148153
return lh;
149154
}
150155

151-
template <typename TT = T, typename = decltype(value_of(std::declval<TT>()) % value_of(std::declval<TT>()))>
156+
template <typename TT = T, typename = decltype(std::declval<TT>() % std::declval<TT>())>
152157
STRONG_NODISCARD
153158
friend
154159
STRONG_CONSTEXPR
155-
T
160+
type
156161
operator%(
157-
T lh,
158-
const T &rh)
162+
type lh,
163+
const type &rh)
159164
{
160165
lh %= rh;
161166
return lh;

include/strong_type/bitarithmetic.hpp

Lines changed: 42 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -20,96 +20,97 @@ namespace strong
2020
{
2121
struct bitarithmetic
2222
{
23-
template <typename T>
23+
template <typename T, typename = void>
2424
class modifier
2525
{
26+
static_assert(impl::always_false<T>,
27+
"Underlying type must support bitarithmetic operations &, | and ^");
28+
};
29+
template <typename T, typename Tag, typename ... Ms>
30+
class modifier<type<T, Tag, Ms...>, impl::void_t<decltype(((std::declval<T&>() |= std::declval<T>()) &= std::declval<T>()) ^= std::declval<T>())>>
31+
{
32+
using type = strong::type<T, Tag, Ms...>;
2633
public:
2734
friend
2835
STRONG_CONSTEXPR
29-
T&
36+
type&
3037
operator&=(
31-
T &lh,
32-
const T &rh)
38+
type &lh,
39+
const type &rh)
3340
noexcept(noexcept(value_of(lh) &= value_of(rh)))
3441
{
35-
using type = underlying_type_t<T>;
36-
value_of(lh) = type(value_of(lh) & value_of(rh));
42+
value_of(lh) = T(value_of(lh) & value_of(rh));
3743
return lh;
3844
}
3945

4046
friend
4147
STRONG_CONSTEXPR
42-
T&
48+
type&
4349
operator|=(
44-
T &lh,
45-
const T &rh)
50+
type &lh,
51+
const type &rh)
4652
noexcept(noexcept(value_of(lh) |= value_of(rh)))
4753
{
48-
using type = underlying_type_t<T>;
49-
value_of(lh) = type(value_of(lh) | value_of(rh));
54+
value_of(lh) = T(value_of(lh) | value_of(rh));
5055
return lh;
5156
}
5257

5358
friend
5459
STRONG_CONSTEXPR
55-
T&
60+
type&
5661
operator^=(
57-
T &lh,
58-
const T &rh)
62+
type &lh,
63+
const type &rh)
5964
noexcept(noexcept(value_of(lh) ^= value_of(rh)))
6065
{
61-
using type = underlying_type_t<T>;
62-
value_of(lh) = type(value_of(lh) ^ value_of(rh));
66+
value_of(lh) = T(value_of(lh) ^ value_of(rh));
6367
return lh;
6468
}
6569

6670
template <typename C>
6771
friend
6872
STRONG_CONSTEXPR
69-
T&
73+
type&
7074
operator<<=(
71-
T &lh,
75+
type &lh,
7276
C c)
7377
noexcept(noexcept(value_of(lh) <<= c))
7478
{
75-
using type = underlying_type_t <T>;
76-
value_of(lh) = type(value_of(lh) << c);
79+
value_of(lh) = T(value_of(lh) << c);
7780
return lh;
7881
}
7982

8083
template <typename C>
8184
friend
8285
STRONG_CONSTEXPR
83-
T&
86+
type&
8487
operator>>=(
85-
T &lh,
88+
type &lh,
8689
C c)
8790
noexcept(noexcept(value_of(lh) >>= c))
8891
{
89-
using type = underlying_type_t<T>;
90-
value_of(lh) = type(value_of(lh) >> c);
92+
value_of(lh) = T(value_of(lh) >> c);
9193
return lh;
9294
}
9395

9496
STRONG_NODISCARD
9597
friend
9698
STRONG_CONSTEXPR
97-
T
99+
type
98100
operator~(
99-
const T &lh)
101+
const type &lh)
100102
{
101-
using type = underlying_type_t<T>;
102103
auto v = value_of(lh);
103-
return T(type(~v));
104+
return type(T(~v));
104105
}
105106

106107
STRONG_NODISCARD
107108
friend
108109
STRONG_CONSTEXPR
109-
T
110+
type
110111
operator&(
111-
T lh,
112-
const T &rh)
112+
type lh,
113+
const type &rh)
113114
{
114115
lh &= rh;
115116
return lh;
@@ -118,10 +119,10 @@ struct bitarithmetic
118119
STRONG_NODISCARD
119120
friend
120121
STRONG_CONSTEXPR
121-
T
122+
type
122123
operator|(
123-
T lh,
124-
const T &rh)
124+
type lh,
125+
const type &rh)
125126
{
126127
lh |= rh;
127128
return lh;
@@ -130,10 +131,10 @@ struct bitarithmetic
130131
STRONG_NODISCARD
131132
friend
132133
STRONG_CONSTEXPR
133-
T
134+
type
134135
operator^(
135-
T lh,
136-
const T &rh)
136+
type lh,
137+
const type &rh)
137138
{
138139
lh ^= rh;
139140
return lh;
@@ -143,9 +144,9 @@ struct bitarithmetic
143144
STRONG_NODISCARD
144145
friend
145146
STRONG_CONSTEXPR
146-
T
147+
type
147148
operator<<(
148-
T lh,
149+
type lh,
149150
C c)
150151
{
151152
lh <<= c;
@@ -156,9 +157,9 @@ struct bitarithmetic
156157
STRONG_NODISCARD
157158
friend
158159
STRONG_CONSTEXPR
159-
T
160+
type
160161
operator>>(
161-
T lh,
162+
type lh,
162163
C c)
163164
{
164165
lh >>= c;

include/strong_type/boolean.hpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,14 @@ namespace strong
2020
{
2121
struct boolean
2222
{
23-
template <typename T>
23+
template <typename T, typename = void>
2424
class modifier
25+
{
26+
static_assert(impl::always_false<T>,
27+
"Underlying type must be convertible to bool");
28+
};
29+
template <typename T>
30+
class modifier<T, impl::void_t<decltype(static_cast<bool>(std::declval<const underlying_type_t<T>>()))>>
2531
{
2632
public:
2733
explicit STRONG_CONSTEXPR operator bool() const

0 commit comments

Comments
 (0)