Skip to content

Commit 98cbb4a

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 98cbb4a

File tree

2 files changed

+366
-0
lines changed

2 files changed

+366
-0
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 & 0 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

@@ -10580,6 +10589,11 @@
1058010589
template<class R, class... ArgTypes>
1058110590
class move_only_function<R(ArgTypes...) @\cv{}@ @\placeholder{ref}@ noexcept(@\placeholder{noex}@)>; // \seebelow
1058210591

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

1344313808
\rSec2[func.search]{Searchers}

0 commit comments

Comments
 (0)