<experimental/propagate_const>
synopsis[propagate_const.syn]
namespace std {
namespace experimental::inline fundamentals_v3 {
// 6.1.2.1, Overview
template <class T> class propagate_const;
// 6.1.2.9, Relational operators
template <class T>
constexpr bool operator==(const propagate_const<T>& pt, nullptr_t);
template <class T>
constexpr bool operator==(nullptr_t, const propagate_const<T>& pu);
template <class T>
constexpr bool operator!=(const propagate_const<T>& pt, nullptr_t);
template <class T>
constexpr bool operator!=(nullptr_t, const propagate_const<T>& pu);
template <class T, class U>
constexpr bool operator==(const propagate_const<T>& pt, const propagate_const<U>& pu);
template <class T, class U>
constexpr bool operator!=(const propagate_const<T>& pt, const propagate_const<U>& pu);
template <class T, class U>
constexpr bool operator<(const propagate_const<T>& pt, const propagate_const<U>& pu);
template <class T, class U>
constexpr bool operator>(const propagate_const<T>& pt, const propagate_const<U>& pu);
template <class T, class U>
constexpr bool operator<=(const propagate_const<T>& pt, const propagate_const<U>& pu);
template <class T, class U>
constexpr bool operator>=(const propagate_const<T>& pt, const propagate_const<U>& pu);
template <class T, class U>
constexpr bool operator==(const propagate_const<T>& pt, const U& u);
template <class T, class U>
constexpr bool operator!=(const propagate_const<T>& pt, const U& u);
template <class T, class U>
constexpr bool operator<(const propagate_const<T>& pt, const U& u);
template <class T, class U>
constexpr bool operator>(const propagate_const<T>& pt, const U& u);
template <class T, class U>
constexpr bool operator<=(const propagate_const<T>& pt, const U& u);
template <class T, class U>
constexpr bool operator>=(const propagate_const<T>& pt, const U& u);
template <class T, class U>
constexpr bool operator==(const T& t, const propagate_const<U>& pu);
template <class T, class U>
constexpr bool operator!=(const T& t, const propagate_const<U>& pu);
template <class T, class U>
constexpr bool operator<(const T& t, const propagate_const<U>& pu);
template <class T, class U>
constexpr bool operator>(const T& t, const propagate_const<U>& pu);
template <class T, class U>
constexpr bool operator<=(const T& t, const propagate_const<U>& pu);
template <class T, class U>
constexpr bool operator>=(const T& t, const propagate_const<U>& pu);
// 6.1.2.10, Specialized algorithms
template <class T>
constexpr void swap(propagate_const<T>& pt, propagate_const<T>& pt2) noexcept(see below);
// 6.1.2.11, Underlying pointer access
template <class T>
constexpr const T& get_underlying(const propagate_const<T>& pt) noexcept;
template <class T>
constexpr T& get_underlying(propagate_const<T>& pt) noexcept;
} // namespace experimental::inline fundamentals_v3
// 6.1.2.12, Hash support
template <class T> struct hash;
template <class T>
struct hash<experimental::fundamentals_v3::propagate_const<T>>;
// 6.1.2.13, Comparison function objects
template <class T> struct equal_to;
template <class T>
struct equal_to<experimental::fundamentals_v3::propagate_const<T>>;
template <class T> struct not_equal_to;
template <class T>
struct not_equal_to<experimental::fundamentals_v3::propagate_const<T>>;
template <class T> struct less;
template <class T>
struct less<experimental::fundamentals_v3::propagate_const<T>>;
template <class T> struct greater;
template <class T>
struct greater<experimental::fundamentals_v3::propagate_const<T>>;
template <class T> struct less_equal;
template <class T>
struct less_equal<experimental::fundamentals_v3::propagate_const<T>>;
template <class T> struct greater_equal;
template <class T>
struct greater_equal<experimental::fundamentals_v3::propagate_const<T>>;
} // namespace std
6.1.2 Class template propagate_const
[propagate_const.tmpl] 6.1.2.1 Overview[propagate_const.overview]
namespace std::experimental::inline fundamentals_v3 {
template <class T> class propagate_const {
public:
using element_type = remove_reference_t<decltype(*declval<T&>())>;
// 6.1.2.4, Constructors
constexpr propagate_const() = default;
propagate_const(const propagate_const& p) = delete;
constexpr propagate_const(propagate_const&& p) = default;
template <class U>
explicit(!is_convertible_v<U, T>) constexpr propagate_const(propagate_const<U>&& pu);
template <class U>
explicit(!is_convertible_v<U, T>) constexpr propagate_const(U&& u);
// 6.1.2.5, Assignment
propagate_const& operator=(const propagate_const& p) = delete;
constexpr propagate_const& operator=(propagate_const&& p) = default;
template <class U>
constexpr propagate_const& operator=(propagate_const<U>&& pu);
template <class U>
constexpr propagate_const& operator=(U&& u);
// 6.1.2.6, Const observers
explicit constexpr operator bool() const;
constexpr const element_type* operator->() const;
constexpr operator const element_type*() const; // Not always defined
constexpr const element_type& operator*() const;
constexpr const element_type* get() const;
// 6.1.2.7, Non-const observers
constexpr element_type* operator->();
constexpr operator element_type*(); // Not always defined
constexpr element_type& operator*();
constexpr element_type* get();
// 6.1.2.8, Modifiers
constexpr void swap(propagate_const& pt) noexcept(is_nothrow_swappable<T>);
private:
T t_; //exposition only
};
} // namespace std::experimental::inline fundamentals_v3
propagate_const
is a wrapper around a pointer-like object type T
which treats the wrapped pointer as a pointer to const
when the wrapper is accessed through a const
access path.
T
[propagate_const.requirements]
T
shall be a cv-unqualified pointer-to-object type or a cv-unqualified class type for which decltype(*declval<T&>())
is an lvalue reference to object type; otherwise the program is ill-formed.
[ Note: propagate_const<const int*>
is well-formed but propagate_const<int* const> is not
. — end note ]
T
[propagate_const.class_type_requirements]
If T
is class type then it shall satisfy the following requirements. In this subclause t
denotes an lvalue of type T
, ct
denotes as_const(t)
.
T
and const T
shall be contextually convertible to bool
.
If T
is implicitly convertible to element_type*
, (element_type*)t == t.get()
shall be true
.
If const T
is implicitly convertible to const element_type*
, (const element_type*)ct == ct.get()
shall be true
.
T
Expression Return type Pre-conditions Operational semantics t.get()
element_type*
ct.get()
const element_type*
or element_type*
t.get() == ct.get()
. *t
element_type&
t.get() != nullptr
*t
refers to the same object as *(t.get())
*ct
const element_type&
or element_type&
ct.get() != nullptr
*ct
refers to the same object as *(ct.get())
t.operator->()
element_type*
t.get() != nullptr
t.operator->() == t.get()
ct.operator->()
const element_type*
or element_type*
ct.get() != nullptr
ct.operator->() == ct.get()
(bool)t
bool
(bool)t
is equivalent to t.get() != nullptr
(bool)ct
bool
(bool)ct
is equivalent to ct.get() != nullptr
6.1.2.4 Constructors[propagate_const.ctor]
template <class U>
explicit(!is_convertible_v<U, T>) constexpr propagate_const(propagate_const<U>&& pu);
is_constructible_v<T, U>
is true.
t_
as if direct-non-list-initializing an object of type T
with the expression std::move(pu.t_)
.
template <class U>
explicit(!is_convertible_v<U, T>) constexpr propagate_const(U&& u);
is_constructible_v<T, U>
is true and decay_t<U>
is not a specialization of propagate_const
.
t_
as if direct-non-list-initializing an object of type T
with the expression std::forward<U>(u)
.
template <class U>
constexpr propagate_const& operator=(propagate_const<U>&& pu);
U
is implicitly convertible to T
.
t_ = std::move(pu.t_)
.
*this
.
template <class U>
constexpr propagate_const& operator=(U&& u);
U
is implicitly convertible to T
and decay_t<U>
is not a specialization of propagate_const
.
t_ = std::forward<U>(u)
.
*this
.
explicit constexpr operator bool() const;
(bool)t_
.
constexpr const element_type* operator->() const;
get() != nullptr
.
get()
.
constexpr operator const element_type*() const;
T
is an object pointer type or has an implicit conversion to const element_type*
.
get()
.
constexpr const element_type& operator*() const;
get() != nullptr
.
*get()
.
constexpr const element_type* get() const;
t_
if T
is an object pointer type, otherwise t_.get()
.
constexpr element_type* operator->();
get() != nullptr
.
get()
.
constexpr operator element_type*();
T
is an object pointer type or has an implicit conversion to element_type*
.
get()
.
constexpr element_type& operator*();
get() != nullptr
.
*get()
.
constexpr element_type* get();
t_
if T
is an object pointer type, otherwise t_.get()
.
constexpr void swap(propagate_const& pt) noexcept(is_nothrow_swappable<T>);
T
are swappable ( C++20 §16.5.3.2 ).
swap(t_, pt.t_)
.
template <class T>
constexpr bool operator==(const propagate_const<T>& pt, nullptr_t);
pt.t_ == nullptr
.
template <class T>
constexpr bool operator==(nullptr_t, const propagate_const<T>& pt);
nullptr == pt.t_
.
template <class T>
constexpr bool operator!=(const propagate_const<T>& pt, nullptr_t);
pt.t_ != nullptr
.
template <class T>
constexpr bool operator!=(nullptr_t, const propagate_const<T>& pt);
nullptr != pt.t_
.
template <class T, class U>
constexpr bool operator==(const propagate_const<T>& pt, const propagate_const<U>& pu);
pt.t_ == pu.t_
.
template <class T, class U>
constexpr bool operator!=(const propagate_const<T>& pt, const propagate_const<U>& pu);
pt.t_ != pu.t_
.
template <class T, class U>
constexpr bool operator<(const propagate_const<T>& pt, const propagate_const<U>& pu);
pt.t_ < pu.t_
.
template <class T, class U>
constexpr bool operator>(const propagate_const<T>& pt, const propagate_const<U>& pu);
pt.t_ > pu.t_
.
template <class T, class U>
constexpr bool operator<=(const propagate_const<T>& pt, const propagate_const<U>& pu);
pt.t_ <= pu.t_
.
template <class T, class U>
constexpr bool operator>=(const propagate_const<T>& pt, const propagate_const<U>& pu);
pt.t_ >= pu.t_
.
template <class T, class U>
constexpr bool operator==(const propagate_const<T>& pt, const U& u);
pt.t_ == u
.
template <class T, class U>
constexpr bool operator!=(const propagate_const<T>& pt, const U& u);
pt.t_ != u
.
template <class T, class U>
constexpr bool operator<(const propagate_const<T>& pt, const U& u);
pt.t_ < u
.
template <class T, class U>
constexpr bool operator>(const propagate_const<T>& pt, const U& u);
pt.t_ > u
.
template <class T, class U>
constexpr bool operator<=(const propagate_const<T>& pt, const U& u);
pt.t_ <= u
.
template <class T, class U>
constexpr bool operator>=(const propagate_const<T>& pt, const U& u);
pt.t_ >= u
.
template <class T, class U>
constexpr bool operator==(const T& t, const propagate_const<U>& pu);
t == pu.t_
.
template <class T, class U>
constexpr bool operator!=(const T& t, const propagate_const<U>& pu);
t != pu.t_
.
template <class T, class U>
constexpr bool operator<(const T& t, const propagate_const<U>& pu);
t < pu.t_
.
template <class T, class U>
constexpr bool operator>(const T& t, const propagate_const<U>& pu);
t > pu.t_
.
template <class T, class U>
constexpr bool operator<=(const T& t, const propagate_const<U>& pu);
t <= pu.t_
.
template <class T, class U>
constexpr bool operator>=(const T& t, const propagate_const<U>& pu);
t >= pu.t_
.
template <class T>
constexpr void swap(propagate_const<T>& pt1, propagate_const<T>& pt2) noexcept(see below);
is_swappable_v<T>
is true
.
pt1.swap(pt2)
.
noexcept
is equivalent to:
noexcept(pt1.swap(pt2))
Access to the underlying object pointer type is through free functions rather than member functions. These functions are intended to resemble cast operations to encourage caution when using them.
template <class T>
constexpr const T& get_underlying(const propagate_const<T>& pt) noexcept;
template <class T>
constexpr T& get_underlying(propagate_const<T>& pt) noexcept;
template <class T>
struct hash<experimental::fundamentals_v3::propagate_const<T>>;
The specialization hash<experimental::fundamentals_v3::propagate_const<T>>
is enabled ( C++20 §20.14.18 ) if and only if hash<T>
is enabled. When enabled, for an object p
of type propagate_const<T>
, hash<experimental::fundamentals_v3::propagate_const<T>>()(p)
evaluates to the same value as hash<T>()(p.t_)
.
template <class T>
struct equal_to<experimental::fundamentals_v3::propagate_const<T>>;
For objects p, q
of type propagate_const<T>
, equal_to<experimental::fundamentals_v3::propagate_const<T>>()(p, q)
shall evaluate to the same value as equal_to<T>()(p.t_, q.t_)
.
equal_to<T>
is well-formed.
equal_to<T>
is well-defined.
template <class T>
struct not_equal_to<experimental::fundamentals_v3::propagate_const<T>>;
For objects p, q
of type propagate_const<T>
, not_equal_to<experimental::fundamentals_v3::propagate_const<T>>()(p, q)
shall evaluate to the same value as not_equal_to<T>()(p.t_, q.t_)
.
not_equal_to<T>
is well-formed.
not_equal_to<T>
is well-defined.
template <class T>
struct less<experimental::fundamentals_v3::propagate_const<T>>;
For objects p, q
of type propagate_const<T>
, less<experimental::fundamentals_v3::propagate_const<T>>()(p, q)
shall evaluate to the same value as less<T>()(p.t_, q.t_)
.
less<T>
is well-formed.
less<T>
is well-defined.
template <class T>
struct greater<experimental::fundamentals_v3::propagate_const<T>>;
For objects p, q
of type propagate_const<T>
, greater<experimental::fundamentals_v3::propagate_const<T>>()(p, q)
shall evaluate to the same value as greater<T>()(p.t_, q.t_)
.
greater<T>
is well-formed.
greater<T>
is well-defined.
template <class T>
struct less_equal<experimental::fundamentals_v3::propagate_const<T>>;
For objects p, q
of type propagate_const<T>
, less_equal<experimental::fundamentals_v3::propagate_const<T>>()(p, q)
shall evaluate to the same value as less_equal<T>()(p.t_, q.t_)
.
less_equal<T>
is well-formed.
less_equal<T>
is well-defined.
template <class T>
struct greater_equal<experimental::fundamentals_v3::propagate_const<T>>;
For objects p, q
of type propagate_const<T>
, greater_equal<experimental::fundamentals_v3::propagate_const<T>>()(p, q)
shall evaluate to the same value as greater_equal<T>()(p.t_, q.t_)
.
greater_equal<T>
is well-formed.
greater_equal<T>
is well-defined.
<experimental/scope>
synopsis[scope.syn]
namespace std::experimental::inline fundamentals_v3 {
// 6.2.2, Class templates scope_exit, scope_fail, and scope_success
template <class EF>
class scope_exit;
template <class EF>
class scope_fail;
template <class EF>
class scope_success;
// 6.2.3, Class template unique_resource
template <class R, class D>
class unique_resource;
// 6.2.3.6, unique_resource creation
template <class R, class D, class S=decay_t<R>>
unique_resource<decay_t<R>, decay_t<D>>
make_unique_resource_checked(R&& r, const S& invalid, D&& d) noexcept(see below);
} // namespace std::experimental::inline fundamentals_v3
6.2.2 Class templates scope_exit
, scope_fail
, and scope_success
[scopeguard.exit]
The class templates scope_exit
, scope_fail
, and scope_success
define scope guards that wrap a function object to be called on their destruction.
In this subclause, the placeholder scope-guard
denotes each of these class templates. In descriptions of the class members, scope-guard
refers to the enclosing class.
namespace std::experimental::inline fundamentals_v3 {
template <class EF> class scope-guard {
public:
template <class EFP>
explicit scope-guard(EFP&& f) noexcept(see below);
scope-guard(scope-guard&& rhs) noexcept(see below);
scope-guard(const scope-guard&) = delete;
scope-guard& operator=(const scope-guard&) = delete;
scope-guard& operator=(scope-guard&&) = delete;
~scope-guard () noexcept(see below);
void release() noexcept;
private:
EF exit_function; // exposition only
bool execute_on_destruction{true}; // exposition only
int uncaught_on_creation{uncaught_exceptions()}; // exposition only
};
template <class EF>
scope-guard(EF) -> scope-guard<EF>;
} // namespace std::experimental::inline fundamentals_v3
The class template scope_exit
is a general-purpose scope guard that calls its exit function when a scope is exited. The class templates scope_fail
and scope_success
share the scope_exit
interface, only the situation when the exit function is called differs.
void grow(vector<int>& v) {
scope_success guard([]{ cout << "Good!" << endl; });
v.resize(1024);
}
— end example ]
[ Note: If the exit function object of a scope_success
or scope_exit
object refers to a local variable of the function where it is defined, e.g., as a lambda capturing the variable by reference, and that variable is used as a return operand in that function, it is possible for that variable to already have been returned when the scope-guard
’s destructor executes, calling the exit function. This can lead to surprising behavior. — end note ]
Template argument EF
shall be a function object type ( C++20 §20.14 ), lvalue reference to function, or lvalue reference to function object type. If EF
is an object type, it shall meet the Cpp17Destructible requirements (C++20 Table 30). Given an lvalue g
of type remove_reference_t<EF>
, the expression g()
shall be well-formed.
The constructor parameter f
in the following constructors shall be a reference to a function or a reference to a function object ( C++20 §20.14 ).
template <class EFP>
explicit scope-guard(EFP&& f) noexcept(
is_nothrow_constructible_v<EF, EFP> ||
is_nothrow_constructible_v<EF, EFP&>);
is_same_v<remove_cvref_t<EFP>, scope-guard>
is false
and is_constructible_v<EF, EFP>
is true
.
f()
is well-formed.
f()
has well-defined behavior. For scope_exit
and scope_fail
, calling f()
does not throw an exception.
EFP
is not an lvalue reference type and is_nothrow_constructible_v<EF, EFP>
is true
, initialize exit_function
with std::forward<EFP>(f)
; otherwise initialize exit_function
with f
. For scope_exit
and scope_fail
, if the initialization of exit_function
throws an exception, calls f()
. [ Note: For scope_success
, f()
will not be called if the initialization fails. — end note ]
exit_function
.
scope-guard(scope-guard&& rhs) noexcept(see below)
(is_nothrow_move_constructible_v<EF> || is_copy_constructible_v<EF>)
is true
.
EF
is an object type:
is_nothrow_move_constructible_v<EF>
is true
, EF
meets the Cpp17MoveConstructible requirements (C++20 Table 26),EF
meets the Cpp17CopyConstructible requirements (C++20 Table 27).is_nothrow_move_constructible_v<EF>
is true
, initializes exit_function
with std::forward<EF>(rhs.exit_function)
, otherwise initializes exit_function
with rhs.exit_function
. Initializes execute_on_destruction
from rhs.execute_on_destruction
and uncaught_on_creation
from rhs.uncaught_on_creation
. If construction succeeds, call rhs.release()
. [ Note: Copying instead of moving provides the strong exception guarantee. — end note ]
execute_on_destruction
yields the value rhs.execute_on_destruction
yielded before the construction. uncaught_on_creation
yields the value rhs.uncaught_on_creation
yielded before the construction.
exit_function
.
noexcept
is equivalent to:
is_nothrow_move_constructible_v<EF> || is_nothrow_copy_constructible_v<EF>
~scope_exit() noexcept(true);
if (execute_on_destruction)
exit_function();
~scope_fail() noexcept(true);
if (execute_on_destruction && uncaught_exceptions() > uncaught_on_creation)
exit_function();
~scope_success() noexcept(noexcept(exit_function()));
if (execute_on_destruction && uncaught_exceptions() <= uncaught_on_creation)
exit_function();
[ Note: If noexcept(exit_function())
is false
, exit_function()
may throw an exception, notwithstanding the restrictions of C++20 §16.5.5.13 . — end note ]
exit_function()
.
void release() noexcept;
execute_on_destruction = false
.
unique_resource
[scopeguard.uniqueres] 6.2.3.1 Overview[scopeguard.uniqueres.overview]
namespace std::experimental::inline fundamentals_v3 {
template <class R, class D> class unique_resource {
public:
// 6.2.3.2, Constructors
unique_resource();
template <class RR, class DD>
unique_resource(RR&& r, DD&& d) noexcept(see below);
unique_resource(unique_resource&& rhs) noexcept(see below);
// 6.2.3.3, Destructor
~unique_resource();
// 6.2.3.4, Assignment
unique_resource& operator=(unique_resource&& rhs) noexcept(see below);
// 6.2.3.5, Other member functions
void reset() noexcept;
template <class RR>
void reset(RR&& r);
void release() noexcept;
const R& get() const noexcept;
see below operator*() const noexcept;
R operator->() const noexcept;
const D& get_deleter() const noexcept;
private:
using R1 = conditional_t<is_reference_v<R>, reference_wrapper<remove_reference_t<R>>, R>; // exposition only
R1 resource; // exposition only
D deleter; // exposition only
bool execute_on_reset{true}; // exposition only
};
template<class R, class D>
unique_resource(R, D) -> unique_resource<R, D>;
} // namespace std::experimental::inline fundamentals_v3
[ Note: unique_resource
is a universal RAII wrapper for resource handles. Typically, such resource handles are of trivial type and come with a factory function and a clean-up or deleter function that do not throw exceptions. The clean-up function together with the result of the creation function is used to create a unique_resource
variable, that on destruction will call the clean-up function. Access to the underlying resource handle is achieved through get()
and in case of a pointer type resource through a set of convenience pointer operator functions. — end note ]
The template argument D
shall meet the requirements of a Cpp17Destructible (C++20 Table 30) function object type ( C++20 §20.14 ), for which, given a lvalue d
of type D
and a lvalue r
of type R
, the expression d(r)
shall be well-formed. D
shall either meet the Cpp17CopyConstructible requirements (C++20 Table 27), or D
shall meet the Cpp17MoveConstructible requirements (C++20 Table 26) and is_nothrow_move_constructible_v<D>
shall be true
.
For the purpose of this subclause, a resource type T
is an object type that meets the requirements of Cpp17CopyConstructible (C++20 Table 27), or is an object type that meets the requirements of Cpp17MoveConstructible (C++20 Table 26) and is_nothrow_move_constructible_v<T>
is true
, or is an lvalue reference to a resource type. R
shall be a resource type.
For the scope of the adjacent subclauses, let RESOURCE
be defined as follows:
resource.get()
if is_reference_v<R>
is true
,resource
otherwise.unique_resource()
is_default_constructible_v<R> && is_default_constructible_v<D>
is true
.
resource
and deleter
; execute_on_reset
is initialized with false
.
template <class RR, class DD>
unique_resource(RR&& r, DD&& d) noexcept(see below)
is_constructible_v<R1, RR> &&
is_constructible_v<D , DD> &&
(is_nothrow_constructible_v<R1, RR> || is_constructible_v<R1,RR&>) &&
(is_nothrow_constructible_v<D , DD> || is_constructible_v<D ,DD&>)
is true
. [ Note: The first two conditions prohibit initialization from an rvalue reference when either R1
or D
is a specialization of reference_wrapper
. — end note ]
d(r)
, d(RESOURCE)
and deleter(RESOURCE)
are well-formed.
d(r)
, d(RESOURCE)
or deleter(RESOURCE)
has well-defined behavior and does not throw an exception.
is_nothrow_constructible_v<R1, RR>
is true
, initializes resource
with std::forward<RR>(r)
, otherwise initializes resource
with r
. Then, if is_nothrow_constructible_v<D, DD>
is true, initializes deleter
with std::forward<DD>(d)
, otherwise initializes deleter
with d
. If initialization of resource
throws an exception, calls d(r)
. If initialization of deleter
throws an exception, calls d(RESOURCE)
. [ Note: The explained mechanism ensures no leaking of resources. — end note ]
resource
or deleter
.
noexcept
is equivalent to:
(is_nothrow_constructible_v<R1, RR> || is_nothrow_constructible_v<R1, RR&>) &&
(is_nothrow_constructible_v<D , DD> || is_nothrow_constructible_v<D , DD&>)
unique_resource(unique_resource&& rhs) noexcept(see below);
resource
as follows:
is_nothrow_move_constructible_v<R1>
is true
, from std::move(rhs.resource)
;rhs.resource
.resource
throws an exception, rhs
is left owning the resource and will free it in due time. — end note ] Then, initialize deleter
as follows:
is_nothrow_move_constructible_v<D>
is true
, from std::move(rhs.deleter)
;rhs.deleter
.deleter
throws an exception and is_nothrow_move_constructible_v<R1>
is true
and rhs.execute_on_reset
is true:
rhs.deleter(RESOURCE);
rhs.release();
Finally, execute_on_reset
is initialized with exchange(rhs.execute_on_reset, false)
. [ Note: The explained mechanism ensures no leaking and no double release of resources. — end note ]
noexcept
is equivalent to:
is_nothrow_move_constructible_v<R1> && is_nothrow_move_constructible_v<D>
~unique_resource();
reset()
.
unique_resource& operator=(unique_resource&& rhs) noexcept(see below);
is_nothrow_move_assignable_v<R1>
is true
, R1
meets the Cpp17MoveAssignable (C++20 Table 28) requirements; otherwise R1
meets the Cpp17CopyAssignable (C++20 Table 29) requirements. If is_nothrow_move_assignable_v<D>
is true
, D
meets the Cpp17MoveAssignable (C++20 Table 28) requirements; otherwise D
meets the Cpp17CopyAssignable (C++20 Table 29) requirements.
reset();
if constexpr (is_nothrow_move_assignable_v<R1>) {
if constexpr (is_nothrow_move_assignable_v<D>) {
resource = std::move(rhs.resource);
deleter = std::move(rhs.deleter);
} else {
deleter = rhs.deleter;
resource = std::move(rhs.resource);
}
} else {
if constexpr (is_nothrow_move_assignable_v<D>) {
resource = rhs.resource;
deleter = std::move(rhs.deleter);
} else {
resource = rhs.resource;
deleter = rhs.deleter;
}
}
execute_on_reset = exchange(rhs.execute_on_reset, false);
[ Note: If a copy of a member throws an exception, this mechanism leaves rhs
intact and *this
in the released state. — end note ]
*this
.
noexcept
is equivalent to:
is_nothrow_move_assignable_v<R1> && is_nothrow_move_assignable_v<D>
void reset() noexcept;
if (execute_on_reset) {
execute_on_reset = false;
deleter(RESOURCE);
}
template <class RR> void reset(RR&& r);
resource
is well-formed.
deleter(r)
is well-formed.
deleter(r)
has well-defined behavior and does not throw an exception.
reset();
if constexpr (is_nothrow_assignable_v<R1&, RR>) {
resource = std::forward<RR>(r);
} else {
resource = as_const(r);
}
execute_on_reset = true;
If copy-assignment of resource
throws an exception, calls deleter(r)
.
void release() noexcept;
execute_on_reset = false
.
const R& get() const noexcept;
resource
.
see below operator*() const noexcept;
is_pointer_v<R>
is true
and is_void_v<remove_pointer_t<R>>
is false
.
return *get();
add_lvalue_reference_t<remove_pointer_t<R>>
.
R operator->() const noexcept;
is_pointer_v<R>
is true
.
get()
.
const D& get_deleter() const noexcept;
deleter
.
unique_resource
creation[scopeguard.uniqueres.create]
template <class R, class D, class S=decay_t<R>>
unique_resource<decay_t<R>, decay_t<D>>
make_unique_resource_checked(R&& resource, const S& invalid, D&& d)
noexcept(is_nothrow_constructible_v<decay_t<R>, R> &&
is_nothrow_constructible_v<decay_t<D>, D>);
(resource == invalid ? true : false)
is well-formed.
(resource == invalid ? true : false)
has well-defined behavior and does not throw an exception.
std::forward<R>(resource), std::forward<D>(d)
, and !bool(resource == invalid)
. Any failure during construction of the return value will not call d(resource)
if bool(resource == invalid)
is true
.
[ Note: This creation function exists to avoid calling a deleter function with an invalid argument. — end note ]
[ Example: The following example shows its use to avoid callingfclose
when fopen
fails.
auto file = make_unique_resource_checked(
::fopen("potentially_nonexistent_file.txt", "r"),
nullptr,
[](auto fptr){ ::fclose(fptr); });
— end example ] 6.3 Metaprogramming and type traits[meta] 6.3.1 Header <experimental/type_traits> synopsis[meta.type.syn]
#include <type_traits>
namespace std::experimental::inline fundamentals_v3 {
// 6.3.2, Other type transformations
template <class> class invocation_type; // not defined
template <class F, class... ArgTypes> class invocation_type<F(ArgTypes...)>;
template <class> class raw_invocation_type; // not defined
template <class F, class... ArgTypes> class raw_invocation_type<F(ArgTypes...)>;
template <class T>
using invocation_type_t = typename invocation_type<T>::type;
template <class T>
using raw_invocation_type_t = typename raw_invocation_type<T>::type;
// 6.3.3, Detection idiom
struct nonesuch;
template <template<class...> class Op, class... Args>
using is_detected = see below;
template <template<class...> class Op, class... Args>
inline constexpr bool is_detected_v
= is_detected<Op, Args...>::value;
template <template<class...> class Op, class... Args>
using detected_t = see below;
template <class Default, template<class...> class Op, class... Args>
using detected_or = see below;
template <class Default, template<class...> class Op, class... Args>
using detected_or_t = typename detected_or<Default, Op, Args...>::type;
template <class Expected, template<class...> class Op, class... Args>
using is_detected_exact = is_same<Expected, detected_t<Op, Args...>>;
template <class Expected, template<class...> class Op, class... Args>
inline constexpr bool is_detected_exact_v
= is_detected_exact<Expected, Op, Args...>::value;
template <class To, template<class...> class Op, class... Args>
using is_detected_convertible = is_convertible<detected_t<Op, Args...>, To>;
template <class To, template<class...> class Op, class... Args>
inline constexpr bool is_detected_convertible_v
= is_detected_convertible<To, Op, Args...>::value;
} // namespace std::experimental::inline fundamentals_v3
6.3.2 Other type transformations[meta.trans.other]
This subclause contains templates that may be used to transform one type to another following some predefined rule.
Each of the templates in this subclause shall be a TransformationTrait ( C++20 §20.15.1 ).
Within this section, define the invocation parameters of INVOKE(f, t1, t2, ..., tN)
as follows, in which T1
is the possibly cv-qualified type of t1
and U1
denotes T1&
if t1
is an lvalue or T1&&
if t1
is an rvalue:
f
is a pointer to a member function of a class T
the invocation parameters are U1
followed by the parameters of f
matched by t2
, ..., tN
.N == 1
and f
is a pointer to member data of a class T
the invocation parameter is U1
.f
is a class object, the invocation parameters are the parameters matching t1
, ..., tN
of the best viable function ( C++20 §12.4.3 ) for the arguments t1
, ..., tN
among the function call operators and surrogate call functions of f
.f
matching t1
, ... tN
.In all of the above cases, if an argument tI
matches the ellipsis in the function's parameter-declaration-clause , the corresponding invocation parameter is defined to be the result of applying the default argument promotions ( C++20 §7.6.1.2 ) to tI
.
S
is defined as
struct S {
int f(double const &) const;
void operator()(int, int);
void operator()(char const *, int i = 2, int j = 3);
void operator()(...);
};
INVOKE(&S::f, S(), 3.5)
are (S &&, double const &)
.INVOKE(S(), 1, 2)
are (int, int)
.INVOKE(S(), "abc", 5)
are (const char *, int)
. The defaulted parameter j
does not correspond to an argument.INVOKE(S(), locale(), 5)
are (locale, int)
. Arguments corresponding to ellipsis maintain their types.Access checking is performed as if in a context unrelated to Fn
and ArgTypes
. Only the validity of the immediate context of the expression is considered. [ Note: The compilation of the expression can result in side effects such as the instantiation of class template specializations and function template specializations, the generation of implicitly-defined functions, and so on. Such side effects are not in the "immediate context" and can result in the program being ill-formed. — end note ]
The member raw_invocation_type<Fn(ArgTypes...)>::type
shall be defined as follows. If the expression INVOKE(declval<Fn>(), declval<ArgTypes>()...)
is ill-formed when treated as an unevaluated operand ( C++20 §7 ), there shall be no member type
. Otherwise:
R
denote result_of_t<Fn(ArgTypes...)>
.Ti
be the invocation parameters of INVOKE(declval<Fn>(), declval<ArgTypes>()...)
.type
shall name the function type R(T1, T2, ...)
.The member invocation_type<Fn(ArgTypes...)>::type
shall be defined as follows. If raw_invocation_type<Fn(ArgTypes...)>::type
does not exist, there shall be no member type
. Otherwise:
A1, A2,
… denote ArgTypes...
R(T1, T2, …)
denote raw_invocation_type_t<Fn(ArgTypes...)>
type
shall name the function type R(U1, U2, …)
where Ui
is decay_t<Ai>
if declval<Ai>()
is an rvalue otherwise Ti
.struct nonesuch {
~nonesuch() = delete;
nonesuch(nonesuch const&) = delete;
void operator=(nonesuch const&) = delete;
};
nonesuch
has no default constructor ( C++20 §11.4.4 ) or initializer-list constructor ( C++20 §9.4.4 ), and is not an aggregate ( C++20 §9.4.1 ).
template <class Default, class AlwaysVoid,
template<class...> class Op, class... Args>
struct DETECTOR { // exposition only
using value_t = false_type;
using type = Default;
};
template <class Default, template<class...> class Op, class... Args>
struct DETECTOR<Default, void_t<Op<Args...>>, Op, Args...> { // exposition only
using value_t = true_type;
using type = Op<Args...>;
};
template <template<class...> class Op, class... Args>
using is_detected = typename DETECTOR<nonesuch, void, Op, Args...>::value_t;
template <template<class...> class Op, class... Args>
using detected_t = typename DETECTOR<nonesuch, void, Op, Args...>::type;
template <class Default, template<class...> class Op, class... Args>
using detected_or = DETECTOR<Default, void, Op, Args...>;
[ Example:
// archetypal helper alias for a copy assignment operation:
template <class T>
using copy_assign_t = decltype(declval<T&>() = declval<T const &>());
// plausible implementation for the is_assignable type trait:
template <class T>
using is_copy_assignable = is_detected<copy_assign_t, T>;
// plausible implementation for an augmented is_assignable type trait
// that also checks the return type:
template <class T>
using is_canonical_copy_assignable = is_detected_exact<T&, copy_assign_t, T>;
— end example ] [ Example:
// archetypal helper alias for a particular type member:
template <class T>
using diff_t = typename T::difference_type;
// alias the type member, if it exists, otherwise alias ptrdiff_t:
template <class Ptr>
using difference_type = detected_or_t<ptrdiff_t, diff_t, Ptr>;
— end example ]
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4