1 /* Proposed SG14 status_code
2 (C) 2018 - 2020 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License in the accompanying file
11 http://www.apache.org/licenses/LICENSE-2.0
13 Unless required by applicable law or agreed to in writing, software
14 distributed under the License is distributed on an "AS IS" BASIS,
15 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 See the License for the specific language governing permissions and
17 limitations under the License.
20 Distributed under the Boost Software License, Version 1.0.
21 (See accompanying file Licence.txt or copy at
22 http://www.boost.org/LICENSE_1_0.txt)
25 #ifndef BOOST_OUTCOME_SYSTEM_ERROR2_STATUS_CODE_HPP
26 #define BOOST_OUTCOME_SYSTEM_ERROR2_STATUS_CODE_HPP
28 #include "status_code_domain.hpp"
30 #if(__cplusplus >= 201700 || _HAS_CXX17) && !defined(BOOST_OUTCOME_SYSTEM_ERROR2_DISABLE_STD_IN_PLACE)
32 #include <utility> // for in_place
34 BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
35 using in_place_t = std::in_place_t;
37 BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
41 BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
42 //! Aliases `std::in_place_t` if on C++ 17 or later, else defined locally.
45 explicit in_place_t() = default;
47 //! Aliases `std::in_place` if on C++ 17 or later, else defined locally.
48 constexpr in_place_t in_place{};
49 BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
52 BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
54 //! Namespace for user injected mixins
57 template <class Base, class T> struct mixin : public Base
63 /*! A tag for an erased value type for `status_code<D>`.
64 Available only if `ErasedType` satisfies `traits::is_move_bitcopying<ErasedType>::value`.
66 BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class ErasedType) //
67 BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(traits::is_move_bitcopying<ErasedType>::value))
70 using value_type = ErasedType;
73 /*! Specialise this template to quickly wrap a third party enumeration into a
74 custom status code domain.
79 BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
80 template <> struct quick_status_code_from_enum<AnotherCode> : quick_status_code_from_enum_defaults<AnotherCode>
82 // Text name of the enum
83 static constexpr const auto domain_name = "Another Code";
84 // Unique UUID for the enum. PLEASE use https://www.random.org/cgi-bin/randbyte?nbytes=16&format=h
85 static constexpr const auto domain_uuid = "{be201f65-3962-dd0e-1266-a72e63776a42}";
86 // Map of each enum value to its text string, and list of semantically equivalent errc's
87 static const std::initializer_list<mapping> &value_mappings()
89 static const std::initializer_list<mapping<AnotherCode>> v = {
90 // Format is: { enum value, "string representation", { list of errc mappings ... } }
91 {AnotherCode::success1, "Success 1", {errc::success}}, //
92 {AnotherCode::goaway, "Go away", {errc::permission_denied}}, //
93 {AnotherCode::success2, "Success 2", {errc::success}}, //
94 {AnotherCode::error2, "Error 2", {}}, //
98 // Completely optional definition of mixin for the status code synthesised from `Enum`. It can be omitted.
99 template <class Base> struct mixin : Base
102 constexpr int custom_method() const { return 42; }
105 BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
108 Note that if the `errc` mapping contains `errc::success`, then
109 the enumeration value is considered to be a successful value.
110 Otherwise it is considered to be a failure value.
112 The first value in the `errc` mapping is the one chosen as the
113 `generic_code` conversion. Other values are used during equivalence
116 template <class Enum> struct quick_status_code_from_enum;
120 template <class T> struct is_status_code
122 static constexpr bool value = false;
124 template <class T> struct is_status_code<status_code<T>>
126 static constexpr bool value = true;
128 template <class T> struct is_erased_status_code
130 static constexpr bool value = false;
132 template <class T> struct is_erased_status_code<status_code<erased<T>>>
134 static constexpr bool value = true;
137 #if !defined(__GNUC__) || defined(__clang__) || __GNUC__ >= 8
138 // From http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4436.pdf
141 template <typename... Ts> struct make_void
145 template <typename... Ts> using void_t = typename make_void<Ts...>::type;
146 template <class...> struct types
150 template <template <class...> class T, class types, class = void> struct test_apply
154 template <template <class...> class T, class... Ts> struct test_apply<T, types<Ts...>, void_t<T<Ts...>>>
156 using type = T<Ts...>;
159 template <template <class...> class T, class... Ts> using test_apply = impl::test_apply<T, impl::types<Ts...>>;
161 template <class T, class... Args> using get_make_status_code_result = decltype(make_status_code(std::declval<T>(), std::declval<Args>()...));
162 template <class... Args> using safe_get_make_status_code_result = test_apply<get_make_status_code_result, Args...>;
166 // ICE avoidance form for GCCs before 8. Note this form doesn't prevent recursive make_status_code ADL instantation,
167 // so in certain corner cases this will break. On the other hand, more useful than an ICE.
170 template <typename... Ts> struct make_void
174 template <typename... Ts> using void_t = typename make_void<Ts...>::type;
175 template <class...> struct types
179 template <typename Types, typename = void> struct make_status_code_rettype
183 template <typename... Args> using get_make_status_code_result = decltype(make_status_code(std::declval<Args>()...));
184 template <typename... Args> struct make_status_code_rettype<types<Args...>, void_t<get_make_status_code_result<Args...>>>
186 using type = get_make_status_code_result<Args...>;
189 template <class... Args> struct safe_get_make_status_code_result
191 using type = typename impl::make_status_code_rettype<impl::types<Args...>>::type;
194 } // namespace detail
196 //! Trait returning true if the type is a status code.
197 template <class T> struct is_status_code
199 static constexpr bool value = detail::is_status_code<typename std::decay<T>::type>::value || detail::is_erased_status_code<typename std::decay<T>::type>::value;
202 /*! A type erased lightweight status code reflecting empty, success, or failure.
203 Differs from `status_code<erased<>>` by being always available irrespective of
204 the domain's value type, but cannot be copied, moved, nor destructed. Thus one
205 always passes this around by const lvalue reference.
207 template <> class BOOST_OUTCOME_SYSTEM_ERROR2_TRIVIAL_ABI status_code<void>
209 template <class T> friend class status_code;
212 //! The type of the domain.
213 using domain_type = void;
214 //! The type of the status code.
215 using value_type = void;
216 //! The type of a reference to a message string.
217 using string_ref = typename status_code_domain::string_ref;
220 const status_code_domain *_domain{nullptr};
223 //! No default construction at type erased level
224 status_code() = default;
225 //! No public copying at type erased level
226 status_code(const status_code &) = default;
227 //! No public moving at type erased level
228 status_code(status_code &&) = default;
229 //! No public assignment at type erased level
230 status_code &operator=(const status_code &) = default;
231 //! No public assignment at type erased level
232 status_code &operator=(status_code &&) = default;
233 //! No public destruction at type erased level
234 ~status_code() = default;
236 //! Used to construct a non-empty type erased status code
237 constexpr explicit status_code(const status_code_domain *v) noexcept
242 // Used to work around triggering a ubsan failure. Do NOT remove!
243 constexpr const status_code_domain *_domain_ptr() const noexcept { return _domain; }
246 //! Return the status code domain.
247 constexpr const status_code_domain &domain() const noexcept { return *_domain; }
248 //! True if the status code is empty.
249 BOOST_OUTCOME_SYSTEM_ERROR2_NODISCARD constexpr bool empty() const noexcept { return _domain == nullptr; }
251 //! Return a reference to a string textually representing a code.
252 BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR20 string_ref message() const noexcept
254 // Avoid MSVC's buggy ternary operator for expensive to destruct things
255 if(_domain != nullptr)
257 return _domain->_do_message(*this);
259 return string_ref("(empty)");
261 //! True if code means success.
262 BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR20 bool success() const noexcept { return (_domain != nullptr) ? !_domain->_do_failure(*this) : false; }
263 //! True if code means failure.
264 BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR20 bool failure() const noexcept { return (_domain != nullptr) ? _domain->_do_failure(*this) : false; }
265 /*! True if code is strictly (and potentially non-transitively) semantically equivalent to another code in another domain.
266 Note that usually non-semantic i.e. pure value comparison is used when the other status code has the same domain.
267 As `equivalent()` will try mapping to generic code, this usually captures when two codes have the same semantic
268 meaning in `equivalent()`.
270 template <class T> BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 bool strictly_equivalent(const status_code<T> &o) const noexcept
272 if(_domain && o._domain)
274 return _domain->_do_equivalent(*this, o);
276 // If we are both empty, we are equivalent
277 if(!_domain && !o._domain)
279 return true; // NOLINT
281 // Otherwise not equivalent
284 /*! True if code is equivalent, by any means, to another code in another domain (guaranteed transitive).
285 Firstly `strictly_equivalent()` is run in both directions. If neither succeeds, each domain is asked
286 for the equivalent generic code and those are compared.
288 template <class T> BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 inline bool equivalent(const status_code<T> &o) const noexcept;
289 #if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
290 //! Throw a code as a C++ exception.
291 BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN void throw_exception() const
293 _domain->_do_throw_exception(*this);
294 abort(); // suppress buggy GCC warning
301 template <class DomainType> struct get_domain_value_type
303 using domain_type = DomainType;
304 using value_type = typename domain_type::value_type;
306 template <class ErasedType> struct get_domain_value_type<erased<ErasedType>>
308 using domain_type = status_code_domain;
309 using value_type = ErasedType;
311 template <class DomainType> class BOOST_OUTCOME_SYSTEM_ERROR2_TRIVIAL_ABI status_code_storage : public status_code<void>
313 using _base = status_code<void>;
316 //! The type of the domain.
317 using domain_type = typename get_domain_value_type<DomainType>::domain_type;
318 //! The type of the status code.
319 using value_type = typename get_domain_value_type<DomainType>::value_type;
320 //! The type of a reference to a message string.
321 using string_ref = typename domain_type::string_ref;
324 static_assert(std::is_move_constructible<value_type>::value || std::is_copy_constructible<value_type>::value, "DomainType::value_type is neither move nor copy constructible!");
325 static_assert(!std::is_default_constructible<value_type>::value || std::is_nothrow_default_constructible<value_type>::value, "DomainType::value_type is not nothrow default constructible!");
326 static_assert(!std::is_move_constructible<value_type>::value || std::is_nothrow_move_constructible<value_type>::value, "DomainType::value_type is not nothrow move constructible!");
327 static_assert(std::is_nothrow_destructible<value_type>::value, "DomainType::value_type is not nothrow destructible!");
330 // Replace the type erased implementations with type aware implementations for better codegen
331 //! Return the status code domain.
332 constexpr const domain_type &domain() const noexcept { return *static_cast<const domain_type *>(this->_domain); }
334 //! Reset the code to empty.
335 BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 void clear() noexcept
337 this->_value.~value_type();
338 this->_domain = nullptr;
339 new(&this->_value) value_type();
342 #if __cplusplus >= 201400 || _MSC_VER >= 1910 /* VS2017 */
343 //! Return a reference to the `value_type`.
344 constexpr value_type &value() &noexcept { return this->_value; }
345 //! Return a reference to the `value_type`.
346 constexpr value_type &&value() &&noexcept { return static_cast<value_type &&>(this->_value); }
348 //! Return a reference to the `value_type`.
349 constexpr const value_type &value() const &noexcept { return this->_value; }
350 //! Return a reference to the `value_type`.
351 constexpr const value_type &&value() const &&noexcept { return static_cast<const value_type &&>(this->_value); }
354 status_code_storage() = default;
355 status_code_storage(const status_code_storage &) = default;
356 BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 status_code_storage(status_code_storage &&o) noexcept
357 : _base(static_cast<status_code_storage &&>(o))
358 , _value(static_cast<status_code_storage &&>(o)._value)
362 status_code_storage &operator=(const status_code_storage &) = default;
363 BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 status_code_storage &operator=(status_code_storage &&o) noexcept
365 this->~status_code_storage();
366 new(this) status_code_storage(static_cast<status_code_storage &&>(o));
369 ~status_code_storage() = default;
372 struct _value_type_constructor
375 template <class... Args>
376 constexpr status_code_storage(_value_type_constructor /*unused*/, const status_code_domain *v, Args &&...args)
378 , _value(static_cast<Args &&>(args)...)
382 } // namespace detail
384 /*! A lightweight, typed, status code reflecting empty, success, or failure.
385 This is the main workhorse of the system_error2 library. Its characteristics reflect the value type
386 set by its domain type, so if that value type is move-only or trivial, so is this.
388 An ADL discovered helper function `make_status_code(T, Args...)` is looked up by one of the constructors.
389 If it is found, and it generates a status code compatible with this status code, implicit construction
392 You may mix in custom member functions and member function overrides by injecting a specialisation of
393 `mixins::mixin<Base, YourDomainType>`. Your mixin must inherit from `Base`.
395 template <class DomainType> class BOOST_OUTCOME_SYSTEM_ERROR2_TRIVIAL_ABI status_code : public mixins::mixin<detail::status_code_storage<DomainType>, DomainType>
397 template <class T> friend class status_code;
398 using _base = mixins::mixin<detail::status_code_storage<DomainType>, DomainType>;
401 //! The type of the domain.
402 using domain_type = DomainType;
403 //! The type of the status code.
404 using value_type = typename domain_type::value_type;
405 //! The type of a reference to a message string.
406 using string_ref = typename domain_type::string_ref;
412 //! Default construction to empty
413 status_code() = default;
415 status_code(const status_code &) = default;
417 status_code(status_code &&) = default; // NOLINT
419 status_code &operator=(const status_code &) = default;
421 status_code &operator=(status_code &&) = default; // NOLINT
422 ~status_code() = default;
424 //! Return a copy of the code.
425 BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 status_code clone() const { return *this; }
427 /***** KEEP THESE IN SYNC WITH ERRORED_STATUS_CODE *****/
428 //! Implicit construction from any type where an ADL discovered `make_status_code(T, Args ...)` returns a `status_code`.
429 BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class T, class... Args, //
430 class MakeStatusCodeResult = typename detail::safe_get_make_status_code_result<T, Args...>::type) // Safe ADL lookup of make_status_code(), returns void if not found
431 BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(!std::is_same<typename std::decay<T>::type, status_code>::value // not copy/move of self
432 && !std::is_same<typename std::decay<T>::type, in_place_t>::value // not in_place_t
433 && is_status_code<MakeStatusCodeResult>::value // ADL makes a status code
434 && std::is_constructible<status_code, MakeStatusCodeResult>::value)) // ADLed status code is compatible
435 constexpr status_code(T &&v, Args &&...args) noexcept(noexcept(make_status_code(std::declval<T>(), std::declval<Args>()...))) // NOLINT
436 : status_code(make_status_code(static_cast<T &&>(v), static_cast<Args &&>(args)...))
439 //! Implicit construction from any `quick_status_code_from_enum<Enum>` enumerated type.
440 BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class Enum, //
441 class QuickStatusCodeType = typename quick_status_code_from_enum<Enum>::code_type) // Enumeration has been activated
442 BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(std::is_constructible<status_code, QuickStatusCodeType>::value)) // Its status code is compatible
443 constexpr status_code(Enum &&v) noexcept(std::is_nothrow_constructible<status_code, QuickStatusCodeType>::value) // NOLINT
444 : status_code(QuickStatusCodeType(static_cast<Enum &&>(v)))
447 //! Explicit in-place construction. Disables if `domain_type::get()` is not a valid expression.
448 template <class... Args>
449 constexpr explicit status_code(in_place_t /*unused */, Args &&...args) noexcept(std::is_nothrow_constructible<value_type, Args &&...>::value)
450 : _base(typename _base::_value_type_constructor{}, &domain_type::get(), static_cast<Args &&>(args)...)
453 //! Explicit in-place construction from initialiser list. Disables if `domain_type::get()` is not a valid expression.
454 template <class T, class... Args>
455 constexpr explicit status_code(in_place_t /*unused */, std::initializer_list<T> il, Args &&...args) noexcept(std::is_nothrow_constructible<value_type, std::initializer_list<T>, Args &&...>::value)
456 : _base(typename _base::_value_type_constructor{}, &domain_type::get(), il, static_cast<Args &&>(args)...)
459 //! Explicit copy construction from a `value_type`. Disables if `domain_type::get()` is not a valid expression.
460 constexpr explicit status_code(const value_type &v) noexcept(std::is_nothrow_copy_constructible<value_type>::value)
461 : _base(typename _base::_value_type_constructor{}, &domain_type::get(), v)
464 //! Explicit move construction from a `value_type`. Disables if `domain_type::get()` is not a valid expression.
465 constexpr explicit status_code(value_type &&v) noexcept(std::is_nothrow_move_constructible<value_type>::value)
466 : _base(typename _base::_value_type_constructor{}, &domain_type::get(), static_cast<value_type &&>(v))
469 /*! Explicit construction from an erased status code. Available only if
470 `value_type` is trivially copyable or move bitcopying, and `sizeof(status_code) <= sizeof(status_code<erased<>>)`.
471 Does not check if domains are equal.
473 BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class ErasedType) //
474 BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(detail::type_erasure_is_safe<ErasedType, value_type>::value))
475 constexpr explicit status_code(const status_code<erased<ErasedType>> &v) noexcept(std::is_nothrow_copy_constructible<value_type>::value)
476 : status_code(detail::erasure_cast<value_type>(v.value()))
478 #if __cplusplus >= 201400
479 assert(v.domain() == this->domain());
483 //! Return a reference to a string textually representing a code.
484 BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR20 string_ref message() const noexcept
486 // Avoid MSVC's buggy ternary operator for expensive to destruct things
487 if(this->_domain != nullptr)
489 return string_ref(this->domain()._do_message(*this));
491 return string_ref("(empty)");
497 template <class DomainType> struct is_move_bitcopying<status_code<DomainType>>
499 static constexpr bool value = is_move_bitcopying<typename DomainType::value_type>::value;
501 } // namespace traits
504 /*! Type erased, move-only status_code, unlike `status_code<void>` which cannot be moved nor destroyed. Available
505 only if `erased<>` is available, which is when the domain's type is trivially
506 copyable or is move relocatable, and if the size of the domain's typed error code is less than or equal to
507 this erased error code. Copy construction is disabled, but if you want a copy call `.clone()`.
509 An ADL discovered helper function `make_status_code(T, Args...)` is looked up by one of the constructors.
510 If it is found, and it generates a status code compatible with this status code, implicit construction
513 template <class ErasedType> class BOOST_OUTCOME_SYSTEM_ERROR2_TRIVIAL_ABI status_code<erased<ErasedType>> : public mixins::mixin<detail::status_code_storage<erased<ErasedType>>, erased<ErasedType>>
515 template <class T> friend class status_code;
516 using _base = mixins::mixin<detail::status_code_storage<erased<ErasedType>>, erased<ErasedType>>;
519 //! The type of the domain (void, as it is erased).
520 using domain_type = void;
521 //! The type of the erased status code.
522 using value_type = ErasedType;
523 //! The type of a reference to a message string.
524 using string_ref = typename _base::string_ref;
527 //! Default construction to empty
528 status_code() = default;
530 status_code(const status_code &) = delete;
532 status_code(status_code &&) = default; // NOLINT
534 status_code &operator=(const status_code &) = delete;
536 status_code &operator=(status_code &&) = default; // NOLINT
537 BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR20 ~status_code()
539 if(nullptr != this->_domain)
541 this->_domain->_do_erased_destroy(*this, sizeof(*this));
545 //! Return a copy of the erased code by asking the domain to perform the erased copy.
546 BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR20 status_code clone() const
548 if(nullptr == this->_domain)
553 this->_domain->_do_erased_copy(x, *this, sizeof(*this));
557 /***** KEEP THESE IN SYNC WITH ERRORED_STATUS_CODE *****/
558 //! Implicit copy construction from any other status code if its value type is trivially copyable and it would fit into our storage
559 BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class DomainType) //
560 BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(std::is_trivially_copyable<typename DomainType::value_type>::value //
561 &&detail::type_erasure_is_safe<value_type, typename DomainType::value_type>::value))
562 constexpr status_code(const status_code<DomainType> &v) noexcept // NOLINT
563 : _base(typename _base::_value_type_constructor{}, v._domain_ptr(), detail::erasure_cast<value_type>(v.value()))
566 //! Implicit move construction from any other status code if its value type is trivially copyable or move bitcopying and it would fit into our storage
567 BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class DomainType) //
568 BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(detail::type_erasure_is_safe<value_type, typename DomainType::value_type>::value))
569 BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 status_code(status_code<DomainType> &&v) noexcept // NOLINT
570 : _base(typename _base::_value_type_constructor{}, v._domain_ptr(), detail::erasure_cast<value_type>(v.value()))
574 //! Implicit construction from any type where an ADL discovered `make_status_code(T, Args ...)` returns a `status_code`.
575 BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class T, class... Args, //
576 class MakeStatusCodeResult = typename detail::safe_get_make_status_code_result<T, Args...>::type) // Safe ADL lookup of make_status_code(), returns void if not found
577 BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(!std::is_same<typename std::decay<T>::type, status_code>::value // not copy/move of self
578 && !std::is_same<typename std::decay<T>::type, value_type>::value // not copy/move of value type
579 && is_status_code<MakeStatusCodeResult>::value // ADL makes a status code
580 && std::is_constructible<status_code, MakeStatusCodeResult>::value)) // ADLed status code is compatible
581 constexpr status_code(T &&v, Args &&...args) noexcept(noexcept(make_status_code(std::declval<T>(), std::declval<Args>()...))) // NOLINT
582 : status_code(make_status_code(static_cast<T &&>(v), static_cast<Args &&>(args)...))
586 //! Implicit construction from any `quick_status_code_from_enum<Enum>` enumerated type.
587 BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class Enum, //
588 class QuickStatusCodeType = typename quick_status_code_from_enum<Enum>::code_type) // Enumeration has been activated
589 BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(std::is_constructible<status_code, QuickStatusCodeType>::value)) // Its status code is compatible
590 constexpr status_code(Enum &&v) noexcept(std::is_nothrow_constructible<status_code, QuickStatusCodeType>::value) // NOLINT
591 : status_code(QuickStatusCodeType(static_cast<Enum &&>(v)))
595 /**** By rights ought to be removed in any formal standard ****/
596 //! Reset the code to empty.
597 BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 void clear() noexcept { *this = status_code(); }
598 //! Return the erased `value_type` by value.
599 constexpr value_type value() const noexcept { return this->_value; }
604 template <class ErasedType> struct is_move_bitcopying<status_code<erased<ErasedType>>>
606 static constexpr bool value = true;
608 } // namespace traits
610 BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END