Skip to content

Commit f9dc7d4

Browse files
authored
Merge 2023-06 LWG Motion 18
P0792R14 function_ref: a type-erased callable reference
2 parents 518d57e + 4066e89 commit f9dc7d4

File tree

2 files changed

+364
-2
lines changed

2 files changed

+364
-2
lines changed

source/support.tex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,7 @@
648648
#define @\defnlibxname{cpp_lib_freestanding_ratio}@ 202306L // freestanding, also in \libheader{ratio}
649649
#define @\defnlibxname{cpp_lib_freestanding_tuple}@ 202306L // freestanding, also in \libheader{tuple}
650650
#define @\defnlibxname{cpp_lib_freestanding_utility}@ 202306L // freestanding, also in \libheader{utility}
651+
#define @\defnlibxname{cpp_lib_function_ref}@ 202306L // also in \libheader{functional}
651652
#define @\defnlibxname{cpp_lib_gcd_lcm}@ 201606L // also in \libheader{numeric}
652653
#define @\defnlibxname{cpp_lib_generator}@ 202207L // also in \libheader{generator}
653654
#define @\defnlibxname{cpp_lib_generic_associative_lookup}@ 201304L // also in \libheader{map}, \libheader{set}

source/utilities.tex

Lines changed: 363 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,15 @@
214214
explicit in_place_index_t() = default;
215215
};
216216
template<size_t I> constexpr in_place_index_t<I> in_place_index{};
217+
218+
// \tcode{nontype} argument tag%
219+
\indexlibraryglobal{nontype_t}%
220+
\indexlibraryglobal{nontype}
221+
template<auto V>
222+
struct nontype_t {
223+
explicit nontype_t() = default;
224+
};
225+
template<auto V> constexpr nontype_t<V> nontype{};
217226
}
218227
\end{codeblock}
219228

@@ -10576,9 +10585,14 @@
1057610585
bool operator==(const function<R(ArgTypes...)>&, nullptr_t) noexcept;
1057710586

1057810587
// \ref{func.wrap.move}, move only wrapper
10579-
template<class... S> class move_only_function; // \notdef
10588+
template<class... S> class move_only_function; // \notdef
10589+
template<class R, class... ArgTypes>
10590+
class move_only_function<R(ArgTypes...) @\cv{}\itcorr[-1]@ @\placeholdernc{ref}@ noexcept(@\placeholdernc{noex}@)>; // \seebelow
10591+
10592+
// \ref{func.wrap.ref}, non-owning wrapper
10593+
template<class... S> class function_ref; // freestanding, \notdef
1058010594
template<class R, class... ArgTypes>
10581-
class move_only_function<R(ArgTypes...) @\cv{}@ @\placeholder{ref}@ noexcept(@\placeholder{noex}@)>; // \seebelow
10595+
class function_ref<R(ArgTypes...) @\cv{}\itcorr[-1]@ noexcept(@\placeholdernc{noex}@)>; // freestanding, \seebelow
1058210596

1058310597
// \ref{func.search}, searchers
1058410598
template<class ForwardIterator1, class BinaryPredicate = equal_to<>>
@@ -13438,6 +13452,353 @@
1343813452
\returns
1343913453
\tcode{true} if \tcode{f} has no target object, otherwise \tcode{false}.
1344013454
\end{itemdescr}
13455+
13456+
\rSec3[func.wrap.ref]{Non-owning wrapper}
13457+
13458+
\rSec4[func.wrap.ref.general]{General}
13459+
13460+
\pnum
13461+
The header provides partial specializations of \tcode{function_ref}
13462+
for each combination of the possible replacements of
13463+
the placeholders \cv{} and \placeholder{noex} where:
13464+
13465+
\begin{itemize}
13466+
\item \cv{} is either const or empty, and
13467+
\item \placeholder{noex} is either \tcode{true} or \tcode{false}.
13468+
\end{itemize}
13469+
13470+
\rSec4[func.wrap.ref.class]{Class template \tcode{function_ref}}
13471+
13472+
\indexlibraryglobal{function_ref}%
13473+
\begin{codeblock}
13474+
namespace std {
13475+
template<class R, class... ArgTypes>
13476+
class function_ref<R(ArgTypes...) @\cv{}@ noexcept(@\placeholder{noex}@)> {
13477+
public:
13478+
// \ref{func.wrap.ref.ctor}, constructors and assignment operators
13479+
template<class F> function_ref(F*) noexcept;
13480+
template<class F> constexpr function_ref(F&&) noexcept;
13481+
template<auto f> constexpr function_ref(nontype_t<f>) noexcept;
13482+
template<auto f, class U> constexpr function_ref(nontype_t<f>, U&&) noexcept;
13483+
template<auto f, class T> constexpr function_ref(nontype_t<f>, @\cv{}@ T*) noexcept;
13484+
13485+
constexpr function_ref(const function_ref&) noexcept = default;
13486+
constexpr function_ref& operator=(const function_ref&) noexcept = default;
13487+
template<class T> function_ref& operator=(T) = delete;
13488+
13489+
// \ref{func.wrap.ref.inv}, invocation
13490+
R operator()(ArgTypes...) const noexcept(@\placeholder{noex}@);
13491+
13492+
private:
13493+
template<class... T>
13494+
static constexpr bool @\exposidnc{is-invocable-using}@ = @\seebelownc@; // \expos
13495+
13496+
R (*@\exposidnc{thunk-ptr}@)(@\exposidnc{BoundEntityType}@, Args&&...) noexcept(@\placeholdernc{noex}@); // \expos
13497+
@\exposidnc{BoundEntityType}@ @\exposidnc{bound-entity}@; // \expos
13498+
};
13499+
13500+
// \ref{func.wrap.ref.deduct}, deduction guides
13501+
template<class F>
13502+
function_ref(F*) -> function_ref<F>;
13503+
template<auto f>
13504+
function_ref(nontype_t<f>) -> function_ref<@\seebelow@>;
13505+
template<auto f>
13506+
function_ref(nontype_t<f>, auto) -> function_ref<@\seebelow@>;
13507+
}
13508+
\end{codeblock}
13509+
13510+
\pnum
13511+
An object of class
13512+
\tcode{function_ref<R(Args...) \cv{} noexcept(\placeholder{noex})>}
13513+
stores a pointer to function \exposid{thunk-ptr} and
13514+
an object \exposid{bound-entity}.
13515+
\exposid{bound-entity} has
13516+
an unspecified trivially copyable type \exposid{BoundEntityType}, that
13517+
models \libconcept{copyable} and
13518+
is capable of storing a pointer to object value or a pointer to function value.
13519+
The type of \exposid{thunk-ptr} is
13520+
\tcode{R(*)(\exposidnc{BoundEntityType}, Args\&\&...) noexcept(\placeholder{noex})}.
13521+
13522+
\pnum
13523+
Each specialization of \tcode{function_ref} is
13524+
a trivially copyable type\iref{term.trivially.copyable.type}
13525+
that models \libconcept{copyable}.
13526+
13527+
\pnum
13528+
Within subclause \ref{func.wrap.ref},
13529+
\tcode{\placeholder{call-args}} is an argument pack with elements such that
13530+
\tcode{decltype((\placeholder{call-args}\linebreak{}))...} denote
13531+
\tcode{Args\&\&...} respectively.
13532+
13533+
\rSec4[func.wrap.ref.ctor]{Constructors and assignment operators}
13534+
13535+
\indextext{function_ref::is-invocable-using@\tcode{function_ref::\exposid{is-invocable-using}}}%
13536+
\begin{itemdecl}
13537+
template<class... T>
13538+
static constexpr bool @\exposid{is-invocable-using}@ = @\seebelow@;
13539+
\end{itemdecl}
13540+
13541+
\begin{itemdescr}
13542+
\pnum
13543+
If \placeholder{noex} is \tcode{true},
13544+
\tcode{\exposid{is-invocable-using}<T...>} is equal to:
13545+
\begin{codeblock}
13546+
is_nothrow_invocable_r_v<R, T..., ArgTypes...>
13547+
\end{codeblock}
13548+
Otherwise, \tcode{\exposid{is-invocable-using}<T...>} is equal to:
13549+
\begin{codeblock}
13550+
is_invocable_r_v<R, T..., ArgTypes...>
13551+
\end{codeblock}
13552+
\end{itemdescr}
13553+
13554+
\indexlibraryctor{function_ref}%
13555+
\begin{itemdecl}
13556+
template<class F> function_ref(F* f) noexcept;
13557+
\end{itemdecl}
13558+
13559+
\begin{itemdescr}
13560+
\pnum
13561+
\constraints
13562+
\begin{itemize}
13563+
\item \tcode{is_function_v<F>} is \tcode{true}, and
13564+
\item \tcode{\exposid{is-invocable-using}<F>} is \tcode{true}.
13565+
\end{itemize}
13566+
13567+
\pnum
13568+
\expects
13569+
\tcode{f} is not a null pointer.
13570+
13571+
\pnum
13572+
\effects
13573+
Initializes
13574+
\exposid{bound-entity} with \tcode{f}, and
13575+
\exposid{thunk-ptr} with the address of a function \tcode{\placeholder{thunk}}
13576+
such that
13577+
\tcode{\placeholder{thunk}(\exposid{bound-entity}, \placeholder{call-args}...)}
13578+
is expression-equivalent\iref{defns.expression.equivalent} to
13579+
\tcode{invoke_r<R>(f, \placeholder{call-args}...)}.
13580+
\end{itemdescr}
13581+
13582+
\indexlibraryctor{function_ref}%
13583+
\begin{itemdecl}
13584+
template<class F> constexpr function_ref(F&& f) noexcept;
13585+
\end{itemdecl}
13586+
13587+
\begin{itemdescr}
13588+
\pnum
13589+
Let \tcode{T} be \tcode{remove_reference_t<F>}.
13590+
13591+
\pnum
13592+
\constraints
13593+
\begin{itemize}
13594+
\item \tcode{remove_cvref_t<F>} is not the same type as \tcode{function_ref},
13595+
\item \tcode{is_member_pointer_v<T>} is \tcode{false}, and
13596+
\item \tcode{\exposid{is-invocable-using}<\cv{} T\&>} is \tcode{true}.
13597+
\end{itemize}
13598+
13599+
\pnum
13600+
\effects
13601+
Initializes
13602+
\exposid{bound-entity} with \tcode{addressof(f)}, and
13603+
\exposid{thunk-ptr} with the address of a function \tcode{\placeholder{thunk}}
13604+
such that
13605+
\tcode{\placeholder{thunk}(\exposid{bound-entity}, \placeholder{call-args}...)}
13606+
is expression-equivalent\iref{defns.expression.equivalent} to
13607+
\tcode{invoke_r<R>(static_cast<\cv{} T\&>(f), \placeholder{call-args}...)}.
13608+
\end{itemdescr}
13609+
13610+
\indexlibraryctor{function_ref}%
13611+
\begin{itemdecl}
13612+
template<auto f> constexpr function_ref(nontype_t<f>) noexcept;
13613+
\end{itemdecl}
13614+
13615+
\begin{itemdescr}
13616+
\pnum
13617+
Let \tcode{F} be \tcode{decltype(f)}.
13618+
13619+
\pnum
13620+
\constraints
13621+
\tcode{\exposid{is-invocable-using}<F>} is \tcode{true}.
13622+
13623+
\pnum
13624+
\mandates
13625+
If \tcode{is_pointer_v<F> || is_member_pointer_v<F>} is \tcode{true},
13626+
then \tcode{f != nullptr} is \tcode{true}.
13627+
13628+
\pnum
13629+
\effects
13630+
Initializes
13631+
\exposid{bound-entity} with a pointer to an unspecified object or
13632+
null pointer value, and
13633+
\exposid{thunk-ptr} with the address of a function \tcode{\placeholder{thunk}}
13634+
such that
13635+
\tcode{\placeholder{thunk}(\exposid{bound-entity}, \placeholder{call-args}...)}
13636+
is expression-equivalent\iref{defns.expression.equivalent} to
13637+
\tcode{invoke_r<R>(f, \placeholder{call-args}...)}.
13638+
\end{itemdescr}
13639+
13640+
\indexlibraryctor{function_ref}%
13641+
\begin{itemdecl}
13642+
template<auto f, class U>
13643+
constexpr function_ref(nontype_t<f>, U&& obj) noexcept;
13644+
\end{itemdecl}
13645+
13646+
\begin{itemdescr}
13647+
\pnum
13648+
Let \tcode{T} be \tcode{remove_reference_t<U>} and
13649+
\tcode{F} be \tcode{decltype(f)}.
13650+
13651+
\pnum
13652+
\constraints
13653+
\begin{itemize}
13654+
\item \tcode{is_rvalue_reference_v<U\&\&>} is \tcode{false}, and
13655+
\item \tcode{\exposid{is-invocable-using}<F, \cv{} T\&>} is \tcode{true}.
13656+
\end{itemize}
13657+
13658+
\pnum
13659+
\mandates
13660+
If \tcode{is_pointer_v<F> || is_member_pointer_v<F>} is \tcode{true},
13661+
then \tcode{f != nullptr} is \tcode{true}.
13662+
13663+
\pnum
13664+
\effects
13665+
Initializes
13666+
\exposid{bound-entity} with \tcode{addressof(obj)}, and
13667+
\exposid{thunk-ptr} with the address of a function \tcode{\placeholder{thunk}}
13668+
such that
13669+
\tcode{\placeholder{thunk}(\exposid{bound-entity}, \placeholder{call-args}...)}
13670+
is expression-equivalent\iref{defns.expression.equivalent} to
13671+
\tcode{invoke_r<R>(f, static_cast<\cv{} T\&>(obj), \placeholder{call-args}...)}.
13672+
\end{itemdescr}
13673+
13674+
\indexlibraryctor{function_ref}%
13675+
\begin{itemdecl}
13676+
template<auto f, class T>
13677+
constexpr function_ref(nontype_t<f>, @\cv{}@ T* obj) noexcept;
13678+
\end{itemdecl}
13679+
13680+
\begin{itemdescr}
13681+
\pnum
13682+
Let \tcode{F} be \tcode{decltype(f)}.
13683+
13684+
\pnum
13685+
\constraints
13686+
\tcode{\exposid{is-invocable-using}<F, \cv{} T*>} is \tcode{true}.
13687+
13688+
\pnum
13689+
\mandates
13690+
If \tcode{is_pointer_v<F> || is_member_pointer_v<F>} is \tcode{true},
13691+
then \tcode{f != nullptr} is \tcode{true}.
13692+
13693+
\pnum
13694+
\expects
13695+
If \tcode{is_member_pointer_v<F>} is \tcode{true},
13696+
\tcode{obj} is not a null pointer.
13697+
13698+
\pnum
13699+
\effects
13700+
Initializes
13701+
\exposid{bound-entity} with \tcode{obj}, and
13702+
\exposid{thunk-ptr} with the address of a function \tcode{\placeholder{thunk}}
13703+
such that
13704+
\tcode{\placeholder{thunk}(\exposid{bound-entity}, \placeholder{call-args}...)}
13705+
is expression-equivalent\iref{defns.expression.equivalent} to
13706+
\tcode{invoke_r<R>(f, obj, \placeholder{call-args}...)}.
13707+
\end{itemdescr}
13708+
13709+
\indexlibrarymember{operator=}{function_ref}%
13710+
\begin{itemdecl}
13711+
template<class T> function_ref& operator=(T) = delete;
13712+
\end{itemdecl}
13713+
13714+
\begin{itemdescr}
13715+
\pnum
13716+
\constraints
13717+
\begin{itemize}
13718+
\item \tcode{T} is not the same type as \tcode{function_ref},
13719+
\item \tcode{is_pointer_v<T>} is \tcode{false}, and
13720+
\item \tcode{T} is not a specialization of \tcode{nontype_t}.
13721+
\end{itemize}
13722+
\end{itemdescr}
13723+
13724+
\rSec4[func.wrap.ref.inv]{Invocation}
13725+
13726+
\indexlibrarymember{operator()}{function_ref}%
13727+
\begin{itemdecl}
13728+
R operator()(ArgTypes... args) const noexcept(@\placeholder{noex}@);
13729+
\end{itemdecl}
13730+
13731+
\begin{itemdescr}
13732+
\pnum
13733+
\effects
13734+
Equivalent to:
13735+
\tcode{return \exposid{thunk-ptr}(\exposid{bound-entity}, std::forward<ArgTypes>(args)...);}
13736+
\end{itemdescr}
13737+
13738+
\rSec4[func.wrap.ref.deduct]{Deduction guides}
13739+
13740+
\begin{itemdecl}
13741+
template<class F>
13742+
function_ref(F*) -> function_ref<F>;
13743+
\end{itemdecl}
13744+
13745+
\begin{itemdescr}
13746+
\pnum
13747+
\constraints
13748+
\tcode{is_function_v<F>} is \tcode{true}.
13749+
\end{itemdescr}
13750+
13751+
\begin{itemdecl}
13752+
template<auto f>
13753+
function_ref(nontype_t<f>) -> function_ref<@\seebelow@>;
13754+
\end{itemdecl}
13755+
13756+
\begin{itemdescr}
13757+
\pnum
13758+
Let \tcode{F} be \tcode{remove_pointer_t<decltype(f)>}.
13759+
13760+
\pnum
13761+
\constraints
13762+
\tcode{is_function_v<F>} is \tcode{true}.
13763+
13764+
\pnum
13765+
\remarks
13766+
The deduced type is \tcode{function_ref<F>}.
13767+
\end{itemdescr}
13768+
13769+
\begin{itemdecl}
13770+
template<auto f, class T>
13771+
function_ref(nontype_t<f>, T&&) -> function_ref<@\seebelow@>;
13772+
\end{itemdecl}
13773+
13774+
\begin{itemdescr}
13775+
\pnum
13776+
Let \tcode{F} be \tcode{decltype(f)}.
13777+
13778+
\pnum
13779+
\constraints
13780+
%FIXME: R and E should be defined outside of these constraints.
13781+
%FIXME: Define R and E via "let" in paragraph above, then use them here and below.
13782+
\begin{itemize}
13783+
\item
13784+
\tcode{F} is of the form
13785+
\tcode{R(G::*)(A...) \cv{} \opt{\&} noexcept(E)} for a type \tcode{G}, or
13786+
\item
13787+
\tcode{F} is of the form
13788+
\tcode{M G::*} for a type \tcode{G} and an object type \tcode{M},
13789+
in which case
13790+
let \tcode{R} be \tcode{invoke_result_t<F, T\&>},
13791+
\tcode{A...} be an empty pack, and
13792+
\tcode{E} be \tcode{false}, or
13793+
\item
13794+
\tcode{F} is of the form
13795+
\tcode{R(*)(G, A...) noexcept(E)} for a type \tcode{G}.
13796+
\end{itemize}
13797+
13798+
\pnum
13799+
\remarks
13800+
The deduced type is \tcode{function_ref<R(A...) noexcept(E)>}.
13801+
\end{itemdescr}
1344113802
\indextext{function object!wrapper|)}
1344213803

1344313804
\rSec2[func.search]{Searchers}

0 commit comments

Comments
 (0)