Skip to content

Commit fcd55ee

Browse files
beinhaerterWerner HenzeWerner Henze
authored
Better use of std::enable_if (#1177)
* this commits adds tests that should fail, but don't * Better use of std::enable_if Replace the occurances of `class = std::enable_if_t<Cond>` and `typename = std::enable_if_t<Cond>` that have been identified in the previous commit with `std::enable_if_t<Cond, bool> = true`. This commit is inspired by #1174, which changed one occurance in the owner header. This commit is aimed to fix all remaining occurances. * fix failing checks - core.cxx_gsl aktualisiert auf [](https://gitlab.avm.de/fos/repos/core.cxx_gsl/-/commit/) - plc.access_lib aktualisiert auf [](https://gitlab.avm.de/fos/repos/plc.access_lib/-/commit/) - plc.common aktualisiert auf [](https://gitlab.avm.de/fos/repos/plc.common/-/commit/) - plc.daemon aktualisiert auf [](https://gitlab.avm.de/fos/repos/plc.daemon/-/commit/) - Test Plan: - --------- Co-authored-by: Werner Henze <[email protected]> Co-authored-by: Werner Henze <[email protected]>
1 parent b8ac820 commit fcd55ee

File tree

6 files changed

+105
-14
lines changed

6 files changed

+105
-14
lines changed

docs/headers.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -91,16 +91,16 @@ See [SL.str.5: Use `std::byte` to refer to byte values that do not necessarily r
9191
### Non-member functions
9292
9393
```cpp
94-
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
94+
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
9595
constexpr byte& operator<<=(byte& b, IntegerType shift) noexcept;
9696
97-
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
97+
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
9898
constexpr byte operator<<(byte b, IntegerType shift) noexcept;
9999
100-
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
100+
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
101101
constexpr byte& operator>>=(byte& b, IntegerType shift) noexcept;
102102
103-
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
103+
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
104104
constexpr byte operator>>(byte b, IntegerType shift) noexcept;
105105
```
106106

@@ -134,7 +134,7 @@ constexpr byte operator~(byte b) noexcept;
134134
Bitwise negation of a `byte`. Flips all bits. Zeroes become ones, ones become zeroes.
135135

136136
```cpp
137-
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
137+
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
138138
constexpr IntegerType to_integer(byte b) noexcept;
139139
```
140140
@@ -310,7 +310,7 @@ auto make_not_null(T&& t) noexcept;
310310
Creates a `gsl::not_null` object, deducing the target type from the type of the argument.
311311

312312
```cpp
313-
template <typename T, typename = std::enable_if_t<std::is_move_assignable<T>::value && std::is_move_constructible<T>::value>>
313+
template <typename T, std::enable_if_t<std::is_move_assignable<T>::value && std::is_move_constructible<T>::value, bool> = true>
314314
void swap(not_null<T>& a, not_null<T>& b);
315315
```
316316

include/gsl/byte

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,25 +91,25 @@ enum class byte_may_alias byte : unsigned char
9191
{
9292
};
9393

94-
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
94+
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
9595
constexpr byte& operator<<=(byte& b, IntegerType shift) noexcept
9696
{
9797
return b = byte(static_cast<unsigned char>(b) << shift);
9898
}
9999

100-
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
100+
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
101101
constexpr byte operator<<(byte b, IntegerType shift) noexcept
102102
{
103103
return byte(static_cast<unsigned char>(b) << shift);
104104
}
105105

106-
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
106+
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
107107
constexpr byte& operator>>=(byte& b, IntegerType shift) noexcept
108108
{
109109
return b = byte(static_cast<unsigned char>(b) >> shift);
110110
}
111111

112-
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
112+
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
113113
constexpr byte operator>>(byte b, IntegerType shift) noexcept
114114
{
115115
return byte(static_cast<unsigned char>(b) >> shift);
@@ -147,7 +147,7 @@ constexpr byte operator^(byte l, byte r) noexcept
147147

148148
constexpr byte operator~(byte b) noexcept { return byte(~static_cast<unsigned char>(b)); }
149149

150-
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
150+
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
151151
constexpr IntegerType to_integer(byte b) noexcept
152152
{
153153
return static_cast<IntegerType>(b);

include/gsl/pointers

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ private:
145145
T ptr_;
146146
};
147147

148-
template <typename T, typename = std::enable_if_t<std::is_move_assignable<T>::value && std::is_move_constructible<T>::value>>
148+
template <typename T, std::enable_if_t<std::is_move_assignable<T>::value && std::is_move_constructible<T>::value, bool> = true>
149149
void swap(not_null<T>& a, not_null<T>& b)
150150
{
151151
a.swap(b);

tests/byte_tests.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
#define GSL_USE_STD_BYTE 0
2020
#include <gsl/byte> // for to_byte, to_integer, byte, operator&, ope...
2121

22+
#include <type_traits>
23+
#include <utility>
24+
2225
using namespace std;
2326
using namespace gsl;
2427

@@ -128,6 +131,48 @@ TEST(byte_tests, aliasing)
128131
EXPECT_TRUE(res == i);
129132
}
130133

134+
#if __cplusplus >= 201703l
135+
using std::void_t;
136+
#else // __cplusplus >= 201703l
137+
template <class...>
138+
using void_t = void;
139+
#endif // __cplusplus < 201703l
140+
141+
template <typename U, typename = void>
142+
static constexpr bool LShiftCompilesFor = false;
143+
template <typename U>
144+
static constexpr bool LShiftCompilesFor<
145+
U, void_t<decltype(gsl::operator<< <float>(declval<gsl::byte>(), declval<U>()))>> = true;
146+
static_assert(!LShiftCompilesFor<float>, "!LShiftCompilesFor<float>");
147+
148+
template <typename U, typename = void>
149+
static constexpr bool RShiftCompilesFor = false;
150+
template <typename U>
151+
static constexpr bool RShiftCompilesFor<
152+
U, void_t<decltype(gsl::operator>> <U>(declval<gsl::byte>(), declval<U>()))>> = true;
153+
static_assert(!RShiftCompilesFor<float>, "!RShiftCompilesFor<float>");
154+
155+
template <typename U, typename = void>
156+
static constexpr bool LShiftAssignCompilesFor = false;
157+
template <typename U>
158+
static constexpr bool LShiftAssignCompilesFor<
159+
U, void_t<decltype(gsl::operator<<= <U>(declval<gsl::byte&>(), declval<U>()))>> = true;
160+
static_assert(!LShiftAssignCompilesFor<float>, "!LShiftAssignCompilesFor<float>");
161+
162+
template <typename U, typename = void>
163+
static constexpr bool RShiftAssignCompilesFor = false;
164+
template <typename U>
165+
static constexpr bool RShiftAssignCompilesFor<
166+
U, void_t<decltype(gsl::operator>>= <U>(declval<gsl::byte&>(), declval<U>()))>> = true;
167+
static_assert(!RShiftAssignCompilesFor<float>, "!RShiftAssignCompilesFor<float>");
168+
169+
template <typename U, typename = void>
170+
static constexpr bool ToIntegerCompilesFor = false;
171+
template <typename U>
172+
static constexpr bool
173+
ToIntegerCompilesFor<U, void_t<decltype(gsl::to_integer<U>(gsl::byte{}))>> = true;
174+
static_assert(!ToIntegerCompilesFor<float>, "!ToIntegerCompilesFor<float>");
175+
131176
} // namespace
132177

133178
#ifdef CONFIRM_COMPILATION_ERRORS

tests/pointers_tests.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,24 @@
33
#include <gsl/pointers>
44

55
#include <memory>
6+
#include <type_traits>
7+
#include <utility>
8+
9+
namespace
10+
{
11+
// Custom pointer type that can be used for gsl::not_null, but for which these cannot be swapped.
12+
struct NotMoveAssignableCustomPtr
13+
{
14+
NotMoveAssignableCustomPtr() = default;
15+
NotMoveAssignableCustomPtr(const NotMoveAssignableCustomPtr&) = default;
16+
NotMoveAssignableCustomPtr& operator=(const NotMoveAssignableCustomPtr&) = default;
17+
NotMoveAssignableCustomPtr(NotMoveAssignableCustomPtr&&) = default;
18+
NotMoveAssignableCustomPtr& operator=(NotMoveAssignableCustomPtr&&) = delete;
19+
20+
bool operator!=(std::nullptr_t) const { return true; }
21+
22+
int dummy{}; // Without this clang warns, that NotMoveAssignableCustomPtr() is unneeded
23+
};
624

725
TEST(pointers_test, swap)
826
{
@@ -17,5 +35,28 @@ TEST(pointers_test, swap)
1735

1836
EXPECT_TRUE(*a == 1);
1937
EXPECT_TRUE(*b == 0);
38+
39+
// Make sure our custom ptr can be used with not_null. The shared_pr is to prevent "unused"
40+
// compiler warnings.
41+
const auto shared_custom_ptr{std::make_shared<NotMoveAssignableCustomPtr>()};
42+
gsl::not_null<NotMoveAssignableCustomPtr> c{*shared_custom_ptr};
43+
EXPECT_TRUE(c.get() != nullptr);
2044
}
2145

46+
#if __cplusplus >= 201703l
47+
using std::void_t;
48+
#else // __cplusplus >= 201703l
49+
template <class...>
50+
using void_t = void;
51+
#endif // __cplusplus < 201703l
52+
53+
template <typename U, typename = void>
54+
static constexpr bool SwapCompilesFor = false;
55+
template <typename U>
56+
static constexpr bool
57+
SwapCompilesFor<U, void_t<decltype(gsl::swap<U>(std::declval<gsl::not_null<U>&>(),
58+
std::declval<gsl::not_null<U>&>()))>> = true;
59+
static_assert(!SwapCompilesFor<NotMoveAssignableCustomPtr>,
60+
"!SwapCompilesFor<NotMoveAssignableCustomPtr>");
61+
62+
} // namespace

tests/span_compatibility_tests.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1005,12 +1005,18 @@ static_assert(std::is_convertible<const std::array<int, 3>&, gsl::span<const int
10051005
"std::is_convertible<const std::array<int, 3>&, gsl::span<const int>>");
10061006

10071007
#if __cplusplus >= 201703l
1008+
using std::void_t;
1009+
#else // __cplusplus >= 201703l
1010+
template <class...>
1011+
using void_t = void;
1012+
#endif // __cplusplus < 201703l
1013+
10081014
template <typename U, typename = void>
10091015
static constexpr bool AsWritableBytesCompilesFor = false;
10101016

10111017
template <typename U>
10121018
static constexpr bool
1013-
AsWritableBytesCompilesFor<U, void_t<decltype(as_writable_bytes(declval<U>()))>> = true;
1019+
AsWritableBytesCompilesFor<U, ::void_t<decltype(as_writable_bytes(declval<U>()))>> = true;
10141020

10151021
static_assert(AsWritableBytesCompilesFor<gsl::span<int>>,
10161022
"AsWritableBytesCompilesFor<gsl::span<int>>");
@@ -1020,4 +1026,3 @@ static_assert(!AsWritableBytesCompilesFor<gsl::span<const int>>,
10201026
"!AsWritableBytesCompilesFor<gsl::span<const int>>");
10211027
static_assert(!AsWritableBytesCompilesFor<gsl::span<const int, 9>>,
10221028
"!AsWritableBytesCompilesFor<gsl::span<const int, 9>>");
1023-
#endif // __cplusplus >= 201703l

0 commit comments

Comments
 (0)