Skip to content

Commit b337c22

Browse files
committed
Add recursive ADL lookup bug workaround for AppleClang and older
C++ 11 compilers.
1 parent 27b0d0f commit b337c22

File tree

4 files changed

+123
-62
lines changed

4 files changed

+123
-62
lines changed

include/status-code/errored_status_code.hpp

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* Proposed SG14 status_code
2-
(C) 2018 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
2+
(C) 2018-2026 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
33
File Created: Jun 2018
44
55
@@ -91,14 +91,14 @@ template <class DomainType> class errored_status_code : public status_code<Domai
9191
SYSTEM_ERROR2_TEMPLATE(class T, class... Args, //
9292
class MakeStatusCodeResult = typename detail::safe_get_make_status_code_result<
9393
T, Args...>::type) // Safe ADL lookup of make_status_code(), returns void if not found
94-
SYSTEM_ERROR2_TREQUIRES(SYSTEM_ERROR2_TPRED(
95-
!std::is_same<typename std::decay<T>::type, errored_status_code>::value // not copy/move of self
96-
&& !std::is_same<typename std::decay<T>::type, in_place_t>::value // not in_place_t
97-
&& is_status_code<MakeStatusCodeResult>::value // ADL makes a status code
98-
&& std::is_constructible<errored_status_code, MakeStatusCodeResult>::value)) // ADLed status code is compatible
94+
SYSTEM_ERROR2_TREQUIRES(
95+
SYSTEM_ERROR2_TPRED(!std::is_same<typename std::decay<T>::type, errored_status_code>::value // not copy/move of self
96+
&& !std::is_same<typename std::decay<T>::type, in_place_t>::value // not in_place_t
97+
&& is_status_code<MakeStatusCodeResult>::value // ADL makes a status code
98+
&& std::is_constructible<_base, MakeStatusCodeResult>::value)) // ADLed status code is compatible
9999
errored_status_code(T &&v,
100100
Args &&...args) noexcept(detail::safe_get_make_status_code_noexcept<T, Args...>::value) // NOLINT
101-
: errored_status_code(make_status_code(static_cast<T &&>(v), static_cast<Args &&>(args)...))
101+
: _base(make_status_code(static_cast<T &&>(v), static_cast<Args &&>(args)...))
102102
{
103103
_check();
104104
}
@@ -264,14 +264,14 @@ class errored_status_code<detail::erased<ErasedType>> : public status_code<detai
264264
SYSTEM_ERROR2_TEMPLATE(class T, class... Args, //
265265
class MakeStatusCodeResult = typename detail::safe_get_make_status_code_result<
266266
T, Args...>::type) // Safe ADL lookup of make_status_code(), returns void if not found
267-
SYSTEM_ERROR2_TREQUIRES(SYSTEM_ERROR2_TPRED(
268-
!std::is_same<typename std::decay<T>::type, errored_status_code>::value // not copy/move of self
269-
&& !std::is_same<typename std::decay<T>::type, value_type>::value // not copy/move of value type
270-
&& is_status_code<MakeStatusCodeResult>::value // ADL makes a status code
271-
&& std::is_constructible<errored_status_code, MakeStatusCodeResult>::value)) // ADLed status code is compatible
267+
SYSTEM_ERROR2_TREQUIRES(
268+
SYSTEM_ERROR2_TPRED(!std::is_same<typename std::decay<T>::type, errored_status_code>::value // not copy/move of self
269+
&& !std::is_same<typename std::decay<T>::type, value_type>::value // not copy/move of value type
270+
&& is_status_code<MakeStatusCodeResult>::value // ADL makes a status code
271+
&& std::is_constructible<_base, MakeStatusCodeResult>::value)) // ADLed status code is compatible
272272
errored_status_code(T &&v,
273273
Args &&...args) noexcept(detail::safe_get_make_status_code_noexcept<T, Args...>::value) // NOLINT
274-
: errored_status_code(make_status_code(static_cast<T &&>(v), static_cast<Args &&>(args)...))
274+
: _base(make_status_code(static_cast<T &&>(v), static_cast<Args &&>(args)...))
275275
{
276276
_check();
277277
}

include/status-code/result.hpp

Lines changed: 48 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* A partial result based on std::variant and proposed std::error
2-
(C) 2020 Niall Douglas <http://www.nedproductions.biz/> (11 commits)
2+
(C) 2020-2026 Niall Douglas <http://www.nedproductions.biz/> (11 commits)
33
File Created: Jan 2020
44
55
Licensed under the Apache License, Version 2.0 (the "License");
@@ -116,7 +116,7 @@ template <class T> class result : protected std::variant<SYSTEM_ERROR2_NAMESPACE
116116
#ifdef _MSC_VER
117117
__declspec(noreturn)
118118
#elif defined(__GNUC__) || defined(__clang__)
119-
__attribute__((noreturn))
119+
__attribute__((noreturn))
120120
#endif
121121
void _ub()
122122
{
@@ -147,25 +147,33 @@ template <class T> class result : protected std::variant<SYSTEM_ERROR2_NAMESPACE
147147

148148
//! Implicit result converting move constructor
149149
SYSTEM_ERROR2_TEMPLATE(class U)
150-
SYSTEM_ERROR2_TREQUIRES(SYSTEM_ERROR2_TPRED(std::is_convertible_v<U, T>)) constexpr result(result<U> &&o, _implicit_converting_constructor_tag = {}) noexcept(std::is_nothrow_constructible_v<T, U>)
150+
SYSTEM_ERROR2_TREQUIRES(SYSTEM_ERROR2_TPRED(std::is_convertible_v<U, T>))
151+
constexpr result(result<U> &&o,
152+
_implicit_converting_constructor_tag = {}) noexcept(std::is_nothrow_constructible_v<T, U>)
151153
: _base(std::move(o))
152154
{
153155
}
154156
//! Implicit result converting copy constructor
155157
SYSTEM_ERROR2_TEMPLATE(class U)
156-
SYSTEM_ERROR2_TREQUIRES(SYSTEM_ERROR2_TPRED(std::is_convertible_v<U, T>)) constexpr result(const result<U> &o, _implicit_converting_constructor_tag = {}) noexcept(std::is_nothrow_constructible_v<T, U>)
158+
SYSTEM_ERROR2_TREQUIRES(SYSTEM_ERROR2_TPRED(std::is_convertible_v<U, T>))
159+
constexpr result(const result<U> &o,
160+
_implicit_converting_constructor_tag = {}) noexcept(std::is_nothrow_constructible_v<T, U>)
157161
: _base(o)
158162
{
159163
}
160164
//! Explicit result converting move constructor
161165
SYSTEM_ERROR2_TEMPLATE(class U)
162-
SYSTEM_ERROR2_TREQUIRES(SYSTEM_ERROR2_TPRED(std::is_constructible_v<T, U>)) constexpr explicit result(result<U> &&o, _explicit_converting_constructor_tag = {}) noexcept(std::is_nothrow_constructible_v<T, U>)
166+
SYSTEM_ERROR2_TREQUIRES(SYSTEM_ERROR2_TPRED(std::is_constructible_v<T, U>))
167+
constexpr explicit result(result<U> &&o,
168+
_explicit_converting_constructor_tag = {}) noexcept(std::is_nothrow_constructible_v<T, U>)
163169
: _base(std::move(o))
164170
{
165171
}
166172
//! Explicit result converting copy constructor
167173
SYSTEM_ERROR2_TEMPLATE(class U)
168-
SYSTEM_ERROR2_TREQUIRES(SYSTEM_ERROR2_TPRED(std::is_constructible_v<T, U>)) constexpr explicit result(const result<U> &o, _explicit_converting_constructor_tag = {}) noexcept(std::is_nothrow_constructible_v<T, U>)
174+
SYSTEM_ERROR2_TREQUIRES(SYSTEM_ERROR2_TPRED(std::is_constructible_v<T, U>))
175+
constexpr explicit result(const result<U> &o,
176+
_explicit_converting_constructor_tag = {}) noexcept(std::is_nothrow_constructible_v<T, U>)
169177
: _base(o)
170178
{
171179
}
@@ -180,31 +188,39 @@ template <class T> class result : protected std::variant<SYSTEM_ERROR2_NAMESPACE
180188
}
181189

182190
//! Implicit in-place converting error constructor
183-
SYSTEM_ERROR2_TEMPLATE(class Arg1, class Arg2, class... Args, long = 5) //
184-
SYSTEM_ERROR2_TREQUIRES(SYSTEM_ERROR2_TPRED(!(std::is_constructible_v<value_type, Arg1, Arg2, Args...> && std::is_constructible_v<error_type, Arg1, Arg2, Args...>) //
191+
SYSTEM_ERROR2_TEMPLATE(class Arg1, class Arg2, class... Args, long = 5) //
192+
SYSTEM_ERROR2_TREQUIRES(SYSTEM_ERROR2_TPRED(!(std::is_constructible_v<value_type, Arg1, Arg2, Args...> &&
193+
std::is_constructible_v<error_type, Arg1, Arg2, Args...>) //
185194
&&std::is_constructible_v<error_type, Arg1, Arg2, Args...>))
186-
constexpr result(Arg1 &&arg1, Arg2 &&arg2, Args &&...args) noexcept(std::is_nothrow_constructible_v<error_type, Arg1, Arg2, Args...>)
195+
constexpr result(Arg1 &&arg1, Arg2 &&arg2,
196+
Args &&...args) noexcept(std::is_nothrow_constructible_v<error_type, Arg1, Arg2, Args...>)
187197
: _base(std::in_place_index<0>, std::forward<Arg1>(arg1), std::forward<Arg2>(arg2), std::forward<Args>(args)...)
188198
{
189199
}
190200

191201
//! Implicit in-place converting value constructor
192-
SYSTEM_ERROR2_TEMPLATE(class Arg1, class Arg2, class... Args, int = 5) //
193-
SYSTEM_ERROR2_TREQUIRES(SYSTEM_ERROR2_TPRED(!(std::is_constructible_v<value_type, Arg1, Arg2, Args...> && std::is_constructible_v<error_type, Arg1, Arg2, Args...>) //
202+
SYSTEM_ERROR2_TEMPLATE(class Arg1, class Arg2, class... Args, int = 5) //
203+
SYSTEM_ERROR2_TREQUIRES(SYSTEM_ERROR2_TPRED(!(std::is_constructible_v<value_type, Arg1, Arg2, Args...> &&
204+
std::is_constructible_v<error_type, Arg1, Arg2, Args...>) //
194205
&&std::is_constructible_v<value_type, Arg1, Arg2, Args...>))
195-
constexpr result(Arg1 &&arg1, Arg2 &&arg2, Args &&...args) noexcept(std::is_nothrow_constructible_v<value_type, Arg1, Arg2, Args...>)
206+
constexpr result(Arg1 &&arg1, Arg2 &&arg2,
207+
Args &&...args) noexcept(std::is_nothrow_constructible_v<value_type, Arg1, Arg2, Args...>)
196208
: _base(std::in_place_index<1>, std::forward<Arg1>(arg1), std::forward<Arg2>(arg2), std::forward<Args>(args)...)
197209
{
198210
}
199211

200-
//! Implicit construction from any type where an ADL discovered `make_status_code(T, Args ...)` returns a `status_code`.
201-
SYSTEM_ERROR2_TEMPLATE(class U, class... Args, //
202-
class MakeStatusCodeResult = typename detail::safe_get_make_status_code_result<U, Args...>::type) // Safe ADL lookup of make_status_code(), returns void if not found
203-
SYSTEM_ERROR2_TREQUIRES(SYSTEM_ERROR2_TPRED(!std::is_same<typename std::decay<U>::type, result>::value // not copy/move of self
204-
&& !std::is_same<typename std::decay<U>::type, value_type>::value // not copy/move of value type
205-
&& is_status_code<MakeStatusCodeResult>::value // ADL makes a status code
206-
&& std::is_constructible<error_type, MakeStatusCodeResult>::value)) // ADLed status code is compatible
207-
constexpr result(U &&v, Args &&...args) noexcept(noexcept(make_status_code(std::declval<U>(), std::declval<Args>()...))) // NOLINT
212+
//! Implicit construction from any type where an ADL discovered `make_status_code(T, Args ...)` returns a
213+
//! `status_code`.
214+
SYSTEM_ERROR2_TEMPLATE(class U, class... Args, //
215+
class MakeStatusCodeResult = typename detail::safe_get_make_status_code_result<
216+
U, Args...>::type) // Safe ADL lookup of make_status_code(), returns void if not found
217+
SYSTEM_ERROR2_TREQUIRES(SYSTEM_ERROR2_TPRED(
218+
!std::is_same<typename std::decay<U>::type, result>::value // not copy/move of self
219+
&& !std::is_same<typename std::decay<U>::type, value_type>::value // not copy/move of value type
220+
&& is_status_code<MakeStatusCodeResult>::value // ADL makes a status code
221+
&& std::is_constructible<error_type, MakeStatusCodeResult>::value)) // ADLed status code is compatible
222+
constexpr result(U &&v, Args &&...args) noexcept(noexcept(make_status_code(std::declval<U>(),
223+
std::declval<Args>()...))) // NOLINT
208224
: _base(std::in_place_index<0>, make_status_code(static_cast<U &&>(v), static_cast<Args &&>(args)...))
209225
{
210226
}
@@ -301,7 +317,7 @@ template <class T> class result : protected std::variant<SYSTEM_ERROR2_NAMESPACE
301317
}
302318

303319
//! Accesses the value, being UB if none exists
304-
constexpr value_type_if_enabled &assume_value() &noexcept
320+
constexpr value_type_if_enabled &assume_value() & noexcept
305321
{
306322
if(!has_value())
307323
{
@@ -310,7 +326,7 @@ template <class T> class result : protected std::variant<SYSTEM_ERROR2_NAMESPACE
310326
return *std::get_if<1>(this);
311327
}
312328
//! Accesses the error, being UB if none exists
313-
constexpr const value_type_if_enabled &assume_value() const &noexcept
329+
constexpr const value_type_if_enabled &assume_value() const & noexcept
314330
{
315331
if(!has_value())
316332
{
@@ -319,7 +335,7 @@ template <class T> class result : protected std::variant<SYSTEM_ERROR2_NAMESPACE
319335
return *std::get_if<1>(this);
320336
}
321337
//! Accesses the error, being UB if none exists
322-
constexpr value_type_if_enabled &&assume_value() &&noexcept
338+
constexpr value_type_if_enabled &&assume_value() && noexcept
323339
{
324340
if(!has_value())
325341
{
@@ -328,7 +344,7 @@ template <class T> class result : protected std::variant<SYSTEM_ERROR2_NAMESPACE
328344
return std::move(*std::get_if<1>(this));
329345
}
330346
//! Accesses the error, being UB if none exists
331-
constexpr const value_type_if_enabled &&assume_value() const &&noexcept
347+
constexpr const value_type_if_enabled &&assume_value() const && noexcept
332348
{
333349
if(!has_value())
334350
{
@@ -338,7 +354,7 @@ template <class T> class result : protected std::variant<SYSTEM_ERROR2_NAMESPACE
338354
}
339355

340356
//! Accesses the error, being UB if none exists
341-
constexpr error_type &assume_error() &noexcept
357+
constexpr error_type &assume_error() & noexcept
342358
{
343359
if(!has_error())
344360
{
@@ -347,7 +363,7 @@ template <class T> class result : protected std::variant<SYSTEM_ERROR2_NAMESPACE
347363
return *std::get_if<0>(this);
348364
}
349365
//! Accesses the error, being UB if none exists
350-
constexpr const error_type &assume_error() const &noexcept
366+
constexpr const error_type &assume_error() const & noexcept
351367
{
352368
if(!has_error())
353369
{
@@ -356,7 +372,7 @@ template <class T> class result : protected std::variant<SYSTEM_ERROR2_NAMESPACE
356372
return *std::get_if<0>(this);
357373
}
358374
//! Accesses the error, being UB if none exists
359-
constexpr error_type &&assume_error() &&noexcept
375+
constexpr error_type &&assume_error() && noexcept
360376
{
361377
if(!has_error())
362378
{
@@ -365,7 +381,7 @@ template <class T> class result : protected std::variant<SYSTEM_ERROR2_NAMESPACE
365381
return std::move(*std::get_if<0>(this));
366382
}
367383
//! Accesses the error, being UB if none exists
368-
constexpr const error_type &&assume_error() const &&noexcept
384+
constexpr const error_type &&assume_error() const && noexcept
369385
{
370386
if(!has_error())
371387
{
@@ -376,13 +392,15 @@ template <class T> class result : protected std::variant<SYSTEM_ERROR2_NAMESPACE
376392
};
377393

378394
//! True if the two results compare equal.
379-
template <class T, class U, typename = decltype(std::declval<T>() == std::declval<U>())> constexpr inline bool operator==(const result<T> &a, const result<U> &b) noexcept
395+
template <class T, class U, typename = decltype(std::declval<T>() == std::declval<U>())>
396+
constexpr inline bool operator==(const result<T> &a, const result<U> &b) noexcept
380397
{
381398
const auto &x = a._internal();
382399
return x == b;
383400
}
384401
//! True if the two results compare unequal.
385-
template <class T, class U, typename = decltype(std::declval<T>() != std::declval<U>())> constexpr inline bool operator!=(const result<T> &a, const result<U> &b) noexcept
402+
template <class T, class U, typename = decltype(std::declval<T>() != std::declval<U>())>
403+
constexpr inline bool operator!=(const result<T> &a, const result<U> &b) noexcept
386404
{
387405
const auto &x = a._internal();
388406
return x != b;

0 commit comments

Comments
 (0)