Skip to content

Commit 37da798

Browse files
committed
P0792R14 function_ref: a type-erased callable reference
1 parent d544cfc commit 37da798

File tree

2 files changed

+368
-0
lines changed

2 files changed

+368
-0
lines changed

source/support.tex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,7 @@
628628
#define @\defnlibxname{cpp_lib_format_ranges}@ 202207L // also in \libheader{format}
629629
#define @\defnlibxname{cpp_lib_formatters}@ 202302L // also in \libheader{stacktrace}, \libheader{thread}
630630
#define @\defnlibxname{cpp_lib_forward_like}@ 202207L // also in \libheader{utility}
631+
#define @\defnlibxname{cpp_lib_function_ref}@ 202306L // also in \libheader{functional}
631632
#define @\defnlibxname{cpp_lib_gcd_lcm}@ 201606L // also in \libheader{numeric}
632633
#define @\defnlibxname{cpp_lib_generator}@ 202207L // also in \libheader{generator}
633634
#define @\defnlibxname{cpp_lib_generic_associative_lookup}@ 201304L // also in \libheader{map}, \libheader{set}

source/utilities.tex

Lines changed: 367 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+
// 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

@@ -10571,6 +10580,11 @@
1057110580
template<class R, class... ArgTypes>
1057210581
class move_only_function<R(ArgTypes...) @\cv{}@ @\placeholder{ref}@ noexcept(@\placeholder{noex}@)>; // \seebelow
1057310582

10583+
// \ref{func.wrap.ref}, non-owning wrapper
10584+
template<class... S> class function_ref; // \notdef, freestanding
10585+
template<class R, class... ArgTypes>
10586+
class function_ref<R(ArgTypes...) @\cv{}@ noexcept(@\placeholder{noex}@)>; // \seebelow, freestanding
10587+
1057410588
// \ref{func.search}, searchers
1057510589
template<class ForwardIterator1, class BinaryPredicate = equal_to<>>
1057610590
class default_searcher; // freestanding
@@ -13431,6 +13445,359 @@
1343113445
\end{itemdescr}
1343213446
\indextext{function object!wrapper|)}
1343313447

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

1343613803
\rSec3[func.search.general]{General}

0 commit comments

Comments
 (0)