proxygen
ExceptionWrapper-inl.h
Go to the documentation of this file.
1 /*
2  * Copyright 2017-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 /*
17  *
18  * Author: Eric Niebler <eniebler@fb.com>
19  */
20 
21 #include <folly/Portability.h>
22 
23 namespace folly {
24 
25 template <class Fn>
27  : public arg_type_<decltype(&Fn::operator())> {};
28 template <class Ret, class Class, class Arg>
29 struct exception_wrapper::arg_type_<Ret (Class::*)(Arg)> {
30  using type = Arg;
31 };
32 template <class Ret, class Class, class Arg>
33 struct exception_wrapper::arg_type_<Ret (Class::*)(Arg) const> {
34  using type = Arg;
35 };
36 template <class Ret, class Arg>
37 struct exception_wrapper::arg_type_<Ret(Arg)> {
38  using type = Arg;
39 };
40 template <class Ret, class Arg>
41 struct exception_wrapper::arg_type_<Ret (*)(Arg)> {
42  using type = Arg;
43 };
44 template <class Ret, class Class>
45 struct exception_wrapper::arg_type_<Ret (Class::*)(...)> {
46  using type = AnyException;
47 };
48 template <class Ret, class Class>
49 struct exception_wrapper::arg_type_<Ret (Class::*)(...) const> {
50  using type = AnyException;
51 };
52 template <class Ret>
53 struct exception_wrapper::arg_type_<Ret(...)> {
54  using type = AnyException;
55 };
56 template <class Ret>
57 struct exception_wrapper::arg_type_<Ret (*)(...)> {
58  using type = AnyException;
59 };
60 
61 template <class Ret, class... Args>
63  return Ret();
64 }
65 
66 inline std::type_info const* exception_wrapper::uninit_type_(
67  exception_wrapper const*) {
68  return &typeid(void);
69 }
70 
71 template <class Ex, typename... As>
73  ::new (static_cast<void*>(&buff_)) Ex(std::forward<As>(as_)...);
74 }
75 
76 template <class Ex>
78  return *static_cast<Ex*>(static_cast<void*>(&buff_));
79 }
80 template <class Ex>
82  return *static_cast<Ex const*>(static_cast<void const*>(&buff_));
83 }
84 
85 inline std::exception const* exception_wrapper::as_exception_or_null_(
86  std::exception const& ex) {
87  return &ex;
88 }
89 inline std::exception const* exception_wrapper::as_exception_or_null_(
90  AnyException) {
91  return nullptr;
92 }
93 
94 static_assert(
95  !kMicrosoftAbiVer || (kMicrosoftAbiVer >= 1900 && kMicrosoftAbiVer <= 2000),
96  "exception_wrapper is untested and possibly broken on your version of "
97  "MSVC");
98 
100  std::exception_ptr const& ptr,
101  std::exception const& e) noexcept {
102  if (!kMicrosoftAbiVer) {
103  return reinterpret_cast<std::uintptr_t>(&e);
104  } else {
105  // On Windows, as of MSVC2017, all thrown exceptions are copied to the stack
106  // first. Thus, we cannot depend on exception references associated with an
107  // exception_ptr to be live for the duration of the exception_ptr. We need
108  // to directly access the heap allocated memory inside the exception_ptr.
109  //
110  // std::exception_ptr is an opaque reinterpret_cast of
111  // std::shared_ptr<__ExceptionPtr>
112  // __ExceptionPtr is a non-virtual class with two members, a union and a
113  // bool. The union contains the now-undocumented EHExceptionRecord, which
114  // contains a struct which contains a void* which points to the heap
115  // allocated exception.
116  // We derive the offset to pExceptionObject via manual means.
118  struct Win32ExceptionPtr {
119  char offset[8 + 4 * sizeof(void*)];
120  void* exceptionObject;
121  } FOLLY_PACK_ATTR;
123 
124  auto* win32ExceptionPtr =
125  reinterpret_cast<std::shared_ptr<Win32ExceptionPtr> const*>(&ptr)
126  ->get();
127  return reinterpret_cast<std::uintptr_t>(win32ExceptionPtr->exceptionObject);
128  }
129 }
131  std::exception_ptr const&,
133  return reinterpret_cast<std::uintptr_t>(e.typeinfo_) + 1;
134 }
136  return 0 == exception_or_type_ % 2;
137 }
139  const {
140  return reinterpret_cast<std::exception const*>(exception_or_type_);
141 }
142 inline std::type_info const* exception_wrapper::ExceptionPtr::as_type_() const {
143  return reinterpret_cast<std::type_info const*>(exception_or_type_ - 1);
144 }
145 
147  exception_wrapper const* from,
149  ::new (static_cast<void*>(&to->eptr_)) ExceptionPtr(from->eptr_);
150 }
154  ::new (static_cast<void*>(&to->eptr_)) ExceptionPtr(std::move(from->eptr_));
155  delete_(from);
156 }
158  that->eptr_.~ExceptionPtr();
159  that->vptr_ = &uninit_;
160 }
162  exception_wrapper const* that) {
163  std::rethrow_exception(that->eptr_.ptr_);
164 }
165 inline std::type_info const* exception_wrapper::ExceptionPtr::type_(
166  exception_wrapper const* that) {
167  if (auto e = get_exception_(that)) {
168  return &typeid(*e);
169  }
170  return that->eptr_.as_type_();
171 }
173  exception_wrapper const* that) {
174  return that->eptr_.has_exception_() ? that->eptr_.as_exception_() : nullptr;
175 }
177  exception_wrapper const* that) {
178  return *that;
179 }
180 
181 template <class Ex>
183  exception_wrapper const* from,
185  ::new (static_cast<void*>(std::addressof(to->buff_.as<Ex>())))
186  Ex(from->buff_.as<Ex>());
187 }
188 template <class Ex>
192  ::new (static_cast<void*>(std::addressof(to->buff_.as<Ex>())))
193  Ex(std::move(from->buff_.as<Ex>()));
194  delete_(from);
195 }
196 template <class Ex>
198  that->buff_.as<Ex>().~Ex();
199  that->vptr_ = &uninit_;
200 }
201 template <class Ex>
202 [[noreturn]] inline void exception_wrapper::InPlace<Ex>::throw_(
203  exception_wrapper const* that) {
204  throw that->buff_.as<Ex>(); // @nolint
205 }
206 template <class Ex>
207 inline std::type_info const* exception_wrapper::InPlace<Ex>::type_(
208  exception_wrapper const*) {
209  return &typeid(Ex);
210 }
211 template <class Ex>
213  exception_wrapper const* that) {
214  return as_exception_or_null_(that->buff_.as<Ex>());
215 }
216 template <class Ex>
218  exception_wrapper const* that) {
219  try {
220  throw_(that);
221  } catch (Ex const& ex) {
222  return exception_wrapper{std::current_exception(), ex};
223  }
224 }
225 
226 template <class Ex>
228  const {
229  throw ex_; // @nolint
230 }
231 template <class Ex>
232 inline std::exception const*
234  return as_exception_or_null_(ex_);
235 }
236 template <class Ex>
237 inline exception_wrapper
239  try {
240  throw_();
241  } catch (Ex& ex) {
242  return exception_wrapper{std::current_exception(), ex};
243  }
244 }
246  exception_wrapper const* from,
248  ::new (static_cast<void*>(std::addressof(to->sptr_))) SharedPtr(from->sptr_);
249 }
253  ::new (static_cast<void*>(std::addressof(to->sptr_)))
254  SharedPtr(std::move(from->sptr_));
255  delete_(from);
256 }
258  that->sptr_.~SharedPtr();
259  that->vptr_ = &uninit_;
260 }
261 [[noreturn]] inline void exception_wrapper::SharedPtr::throw_(
262  exception_wrapper const* that) {
263  that->sptr_.ptr_->throw_();
265 }
266 inline std::type_info const* exception_wrapper::SharedPtr::type_(
267  exception_wrapper const* that) {
268  return that->sptr_.ptr_->info_;
269 }
270 inline std::exception const* exception_wrapper::SharedPtr::get_exception_(
271  exception_wrapper const* that) {
272  return that->sptr_.ptr_->get_exception_();
273 }
275  exception_wrapper const* that) {
276  return that->sptr_.ptr_->get_exception_ptr_();
277 }
278 
279 template <class Ex, typename... As>
281  ThrownTag,
283  As&&... as)
284  : eptr_{std::make_exception_ptr(Ex(std::forward<As>(as)...)),
285  reinterpret_cast<std::uintptr_t>(std::addressof(typeid(Ex))) + 1u},
287 
288 template <class Ex, typename... As>
290  OnHeapTag,
292  As&&... as)
293  : sptr_{std::make_shared<SharedPtr::Impl<Ex>>(std::forward<As>(as)...)},
295 
296 template <class Ex, typename... As>
298  InSituTag,
300  As&&... as)
301  : buff_{in_place_type<Ex>, std::forward<As>(as)...},
303 
305  : exception_wrapper{} {
306  (vptr_ = that.vptr_)->move_(&that, this); // Move into *this, won't throw
307 }
308 
310  exception_wrapper const& that) noexcept
311  : exception_wrapper{} {
312  that.vptr_->copy_(&that, this); // Copy into *this, won't throw
313  vptr_ = that.vptr_;
314 }
315 
316 // If `this == &that`, this move assignment operator leaves the object in a
317 // valid but unspecified state.
319  exception_wrapper&& that) noexcept {
320  vptr_->delete_(this); // Free the current exception
321  (vptr_ = that.vptr_)->move_(&that, this); // Move into *this, won't throw
322  return *this;
323 }
324 
326  exception_wrapper const& that) noexcept {
327  exception_wrapper(that).swap(*this);
328  return *this;
329 }
330 
332  reset();
333 }
334 
335 template <class Ex>
337  std::exception_ptr ptr,
338  Ex& ex) noexcept
340  assert(eptr_.ptr_);
341 }
342 
343 namespace exception_wrapper_detail {
344 template <class Ex>
345 Ex&& dont_slice(Ex&& ex) {
346  assert(typeid(ex) == typeid(_t<std::decay<Ex>>) ||
347  !"Dynamic and static exception types don't match. Exception would "
348  "be sliced when storing in exception_wrapper.");
349  return std::forward<Ex>(ex);
350 }
351 } // namespace exception_wrapper_detail
352 
353 template <
354  class Ex,
355  class Ex_,
362  in_place_type<Ex_>,
363  exception_wrapper_detail::dont_slice(std::forward<Ex>(ex))} {}
364 
365 template <
366  class Ex,
367  class Ex_,
372  in_place_type<Ex_>,
373  exception_wrapper_detail::dont_slice(std::forward<Ex>(ex))} {}
374 
375 template <
376  class Ex,
377  typename... As,
381  in_place_type<Ex>,
382  std::forward<As>(as)...} {}
383 
385  exception_wrapper tmp(std::move(that));
386  that = std::move(*this);
387  *this = std::move(tmp);
388 }
389 
390 inline exception_wrapper::operator bool() const noexcept {
391  return vptr_ != &uninit_;
392 }
393 
395  return !static_cast<bool>(*this);
396 }
397 
399  vptr_->delete_(this);
400 }
401 
403  return vptr_ == &ExceptionPtr::ops_;
404 }
405 
406 inline std::exception* exception_wrapper::get_exception() noexcept {
407  return const_cast<std::exception*>(vptr_->get_exception_(this));
408 }
409 inline std::exception const* exception_wrapper::get_exception() const noexcept {
410  return vptr_->get_exception_(this);
411 }
412 
413 template <typename Ex>
415  Ex* object{nullptr};
416  with_exception([&](Ex& ex) { object = &ex; });
417  return object;
418 }
419 
420 template <typename Ex>
422  Ex const* object{nullptr};
423  with_exception([&](Ex const& ex) { object = &ex; });
424  return object;
425 }
426 
427 inline std::exception_ptr const&
429  // Computing an exception_ptr is expensive so cache the result.
430  return (*this = vptr_->get_exception_ptr_(this)).eptr_.ptr_;
431 }
433  return vptr_->get_exception_ptr_(this).eptr_.ptr_;
434 }
435 
436 inline std::type_info const& exception_wrapper::none() noexcept {
437  return typeid(void);
438 }
439 inline std::type_info const& exception_wrapper::unknown() noexcept {
440  return typeid(Unknown);
441 }
442 
443 inline std::type_info const& exception_wrapper::type() const noexcept {
444  return *vptr_->type_(this);
445 }
446 
448  if (auto e = get_exception()) {
449  return class_name() + ": " + e->what();
450  }
451  return class_name();
452 }
453 
455  auto& ti = type();
456  return ti == none()
457  ? ""
458  : ti == unknown() ? "<unknown exception>" : folly::demangle(ti);
459 }
460 
461 template <class Ex>
463  return with_exception([](Ex const&) {});
464 }
465 
466 [[noreturn]] inline void exception_wrapper::throw_exception() const {
467  vptr_->throw_(this);
468  onNoExceptionError(__func__);
469 }
470 
471 template <class Ex>
472 [[noreturn]] inline void exception_wrapper::throw_with_nested(Ex&& ex) const {
473  try {
474  throw_exception();
475  } catch (...) {
476  std::throw_with_nested(std::forward<Ex>(ex));
477  }
478 }
479 
480 template <class CatchFn, bool IsConst>
483  static_assert(
485  "Always catch exceptions by reference.");
486  static_assert(
487  !IsConst || std::is_const<_t<std::remove_reference<type>>>::value,
488  "handle() or with_exception() called on a const exception_wrapper "
489  "and asked to catch a non-const exception. Handler will never fire. "
490  "Catch exception by const reference to fix this.");
491 };
492 
493 // Nests a throw in the proper try/catch blocks
494 template <bool IsConst>
496  bool* handled_;
497 
498  template <
499  class ThrowFn,
500  class CatchFn,
502  auto operator()(ThrowFn&& th, CatchFn& ca) const {
504  return [th = std::forward<ThrowFn>(th), &ca, handled_ = handled_] {
505  try {
506  th();
507  } catch (Ex& e) {
508  // If we got here because a catch function threw, rethrow.
509  if (*handled_) {
510  throw;
511  }
512  *handled_ = true;
513  ca(e);
514  }
515  };
516  }
517 
518  template <
519  class ThrowFn,
520  class CatchFn,
522  auto operator()(ThrowFn&& th, CatchFn& ca) const {
523  return [th = std::forward<ThrowFn>(th), &ca, handled_ = handled_] {
524  try {
525  th();
526  } catch (...) {
527  // If we got here because a catch function threw, rethrow.
528  if (*handled_) {
529  throw;
530  }
531  *handled_ = true;
532  ca();
533  }
534  };
535  }
536 };
537 
538 // When all the handlers expect types derived from std::exception, we can
539 // sometimes invoke the handlers without throwing any exceptions.
540 template <bool IsConst>
543 
544  template <
545  class ThrowFn,
546  class CatchFn,
548  auto operator()(ThrowFn&& th, CatchFn& ca) const {
550  return
551  [th = std::forward<ThrowFn>(th), &ca](auto&& continuation) -> StdEx* {
552  if (auto e = const_cast<StdEx*>(th(continuation))) {
553  if (auto e2 = dynamic_cast<_t<std::add_pointer<Ex>>>(e)) {
554  ca(*e2);
555  } else {
556  return e;
557  }
558  }
559  return nullptr;
560  };
561  }
562 
563  template <
564  class ThrowFn,
565  class CatchFn,
567  auto operator()(ThrowFn&& th, CatchFn& ca) const {
568  return [th = std::forward<ThrowFn>(th), &ca](auto &&) -> StdEx* {
569  // The following continuation causes ca() to execute if *this contains
570  // an exception /not/ derived from std::exception.
571  auto continuation = [&ca](StdEx* e) {
572  return e != nullptr ? e : ((void)ca(), nullptr);
573  };
574  if (th(continuation) != nullptr) {
575  ca();
576  }
577  return nullptr;
578  };
579  }
580 };
581 
582 // Called when some types in the catch clauses are not derived from
583 // std::exception.
584 template <class This, class... CatchFns>
585 inline void
586 exception_wrapper::handle_(std::false_type, This& this_, CatchFns&... fns) {
587  bool handled = false;
588  auto impl = exception_wrapper_detail::fold(
590  [&] { this_.throw_exception(); },
591  fns...);
592  impl();
593 }
594 
595 // Called when all types in the catch clauses are either derived from
596 // std::exception or a catch-all clause.
597 template <class This, class... CatchFns>
598 inline void
599 exception_wrapper::handle_(std::true_type, This& this_, CatchFns&... fns) {
600  using StdEx = exception_wrapper_detail::
602  auto impl = exception_wrapper_detail::fold(
604  [&](auto&& continuation) {
605  return continuation(
606  const_cast<StdEx*>(this_.vptr_->get_exception_(&this_)));
607  },
608  fns...);
609  // This continuation gets evaluated if CatchFns... does not include a
610  // catch-all handler. It is a no-op.
611  auto continuation = [](StdEx* ex) { return ex; };
612  if (nullptr != impl(continuation)) {
613  this_.throw_exception();
614  }
615 }
616 
617 namespace exception_wrapper_detail {
618 template <class Ex, class Fn>
619 struct catch_fn {
620  Fn fn_;
621  auto operator()(Ex& ex) {
622  return fn_(ex);
623  }
624 };
625 
626 template <class Ex, class Fn>
627 inline catch_fn<Ex, Fn> catch_(Ex*, Fn fn) {
628  return {std::move(fn)};
629 }
630 template <class Fn>
631 inline Fn catch_(void const*, Fn fn) {
632  return fn;
633 }
634 } // namespace exception_wrapper_detail
635 
636 template <class Ex, class This, class Fn>
637 inline bool exception_wrapper::with_exception_(This& this_, Fn fn_) {
638  if (!this_) {
639  return false;
640  }
641  bool handled = true;
643  static_cast<Ex*>(nullptr), std::move(fn_));
644  auto&& all = [&](...) { handled = false; };
645  handle_(IsStdException<arg_type<decltype(fn)>>{}, this_, fn, all);
646  return handled;
647 }
648 
649 template <class Ex, class Fn>
651  return with_exception_<Ex>(*this, std::move(fn));
652 }
653 template <class Ex, class Fn>
654 inline bool exception_wrapper::with_exception(Fn fn) const {
655  return with_exception_<Ex const>(*this, std::move(fn));
656 }
657 
658 template <class... CatchFns>
659 inline void exception_wrapper::handle(CatchFns... fns) {
660  using AllStdEx =
662  if (!*this) {
663  onNoExceptionError(__func__);
664  }
665  this->handle_(AllStdEx{}, *this, fns...);
666 }
667 template <class... CatchFns>
668 inline void exception_wrapper::handle(CatchFns... fns) const {
669  using AllStdEx =
671  if (!*this) {
672  onNoExceptionError(__func__);
673  }
674  this->handle_(AllStdEx{}, *this, fns...);
675 }
676 
677 } // namespace folly
void * ptr
bool has_exception_ptr() const noexcept
folly::fbstring what() const
void * object
Definition: AtFork.cpp:32
_t< arg_type_< Fn >> arg_type
static void delete_(exception_wrapper *that)
static exception_wrapper get_exception_ptr_(exception_wrapper const *that)
static bool with_exception_(This &this_, Fn fn_)
FOLLY_PACK_PUSH struct folly::Unaligned< T, typename std::enable_if< std::is_pod< T >::value >::type > FOLLY_PACK_ATTR
void handle(CatchFns...fns)
std::type_info const * as_type_() const
static std::type_info const * type_(exception_wrapper const *)
static std::type_info const & unknown() noexcept
static std::exception const * get_exception_(exception_wrapper const *that)
volatile bool handled
bool is_compatible_with() const noexcept
std::type_info const *(* type_)(exception_wrapper const *)
#define FOLLY_REQUIRES(...)
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
static std::exception const * as_exception_or_null_(std::exception const &ex)
std::is_base_of< std::exception, _t< std::decay< Ex >>> IsStdException
exception_wrapper & operator=(exception_wrapper &&that) noexcept
static void move_(exception_wrapper *from, exception_wrapper *to)
static std::type_info const & none() noexcept
#define FOLLY_REQUIRES_DEF(...)
internal::ArgsMatcher< InnerMatcher > Args(const InnerMatcher &matcher)
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
static std::type_info const * type_(exception_wrapper const *that)
requires E e noexcept(noexcept(s.error(std::move(e))))
in_place_tag(&)(in_place_tag) in_place_t
Definition: Utility.h:229
folly::fbstring class_name() const
auto operator()(ThrowFn &&th, CatchFn &ca) const
static exception_wrapper get_exception_ptr_(exception_wrapper const *that)
exception_wrapper_detail::AddConstIf< B, T > AddConstIf
constexpr auto kMicrosoftAbiVer
Definition: Portability.h:397
bool_constant< true > true_type
Definition: gtest-port.h:2210
static void move_(exception_wrapper *from, exception_wrapper *to)
_t< std::conditional< !IsStdException< T >::value, ThrownTag, _t< std::conditional< sizeof(T)<=sizeof(Buffer::Storage)&&alignof(T)<=alignof(Buffer::Storage)&&noexcept(T(std::declval< T && >()))&&noexcept(T(std::declval< T const & >())), InSituTag, OnHeapTag >>>> PlacementOf
static std::type_info const * type_(exception_wrapper const *that)
static void copy_(exception_wrapper const *from, exception_wrapper *to)
std::exception * get_exception() noexcept
FOLLY_ALWAYS_INLINE void assume_unreachable()
Definition: Assume.h:59
FOLLY_PACK_PUSH
std::exception_ptr const & to_exception_ptr() noexcept
static void onNoExceptionError(char const *name)
std::enable_if< detail::is_chrono_conversion< Tgt, Src >::value, Tgt >::type to(const Src &value)
Definition: Conv.h:677
typename T::type _t
Definition: Traits.h:171
static std::exception const * get_exception_(exception_wrapper const *that)
static exception_wrapper get_exception_ptr_(exception_wrapper const *that)
void swap(exception_wrapper &that) noexcept
Swaps the value of *this with the value of that
static void throw_(exception_wrapper const *that)
static std::type_info const * uninit_type_(exception_wrapper const *)
static const char *const value
Definition: Conv.cpp:50
std::exception const * as_exception_() const
static void delete_(exception_wrapper *that)
auto operator()(ThrowFn &&th, CatchFn &ca) const
PUSHMI_INLINE_VAR constexpr struct folly::pushmi::operators::from_fn from
std::type_info const & type() const noexcept
arg_type< _t< std::decay< CatchFn >>> type
catch_fn< Ex, Fn > catch_(Ex *, Fn fn)
static void move_(exception_wrapper *from, exception_wrapper *to)
void(* delete_)(exception_wrapper *)
void(* copy_)(exception_wrapper const *, exception_wrapper *)
static void copy_(exception_wrapper const *from, exception_wrapper *to)
static std::exception const * get_exception_(exception_wrapper const *that)
static std::uintptr_t as_int_(std::exception_ptr const &ptr, std::exception const &e) noexcept
static VTable const uninit_
exception_wrapper get_exception_ptr_() const noexceptoverride
std::is_same< arg_type< _t< std::decay< CatchFn >>>, AnyException > IsCatchAll
static void delete_(exception_wrapper *that)
FOLLY_ALWAYS_INLINE FOLLY_ATTR_VISIBILITY_HIDDEN auto fold(Fn &&, A &&a)
const
Definition: upload.py:398
static void handle_(std::false_type, This &this_, CatchFns &...fns)
static void throw_(exception_wrapper const *that)
uint64_t value(const typename LockFreeRingBuffer< T, Atom >::Cursor &rbcursor)
bool_constant< false > false_type
Definition: gtest-port.h:2209
exception_wrapper(* get_exception_ptr_)(exception_wrapper const *)
void(* throw_)(exception_wrapper const *)
bool operator!() const noexcept
static void throw_(exception_wrapper const *that)
std::exception const *(* get_exception_)(exception_wrapper const *)
void throw_with_nested(Ex &&ex) const
Collect as()
Definition: Base.h:811
_t< std::conditional< If, const T, T >> AddConstIf
AddConstIf< IsConst, std::exception > StdEx
fbstring demangle(const char *name)
Definition: Demangle.cpp:111
std::exception const * get_exception_() const noexceptoverride
Composed all(Predicate pred=Predicate())
Definition: Base.h:786
static bool is_const(T &&)
static void copy_(exception_wrapper const *from, exception_wrapper *to)