Skip to content

Commit a91769e

Browse files
burblebeetkoeppe
authored andcommitted
P0792R14 function_ref: a type-erased callable reference
Editorial notes: - [func.wrap.ref.class] Fix reference for "trivially copyable type". - [func.wrap.ref.class] Change "this subclause" to "subclause [func.wrap.ref]" to account for the external use of "call-args".
1 parent 518d57e commit a91769e

File tree

2 files changed

+366
-2
lines changed

2 files changed

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

1344313806
\rSec2[func.search]{Searchers}

0 commit comments

Comments
 (0)