23#include <initializer_list>
27#include <source_location>
36 template <
template <
typename>
class Handle,
typename I>
39 inline std::vector<DataObjID>
to_DataObjID(
const std::vector<std::string>& in ) {
40 std::vector<DataObjID> out;
41 out.reserve( in.size() );
42 std::transform( in.begin(), in.end(), std::back_inserter( out ),
43 [](
const std::string& i ) { return DataObjID{ i }; } );
52 typename T::value_type;
62 template <is_optional T>
64 using type = T::value_type;
73 template <
typename F,
typename Arg>
76 return std::invoke( std::forward<F>( f ), std::forward<Arg>( arg ) );
78 template <
typename F, is_optional Arg>
80 if ( arg ) std::invoke( std::forward<F>( f ), *std::forward<Arg>( arg ) );
82 } invoke_optionally{};
85 template <
typename Value, auto>
86 using repeat_t = Value;
87 template <
typename Value, auto N>
89 decltype( []<std::size_t... I>( std::index_sequence<I...> ) -> std::tuple<repeat_t<Value, I>...> {
90 }( std::make_index_sequence<N>{} ) );
92 template <
typename Value, std::size_t... I>
94 return std::make_tuple( ( (
void)I, Value{} )... );
97 template <
typename Value, auto N>
102 template <std::derived_from<DataObject> Out1, std::convertible_to<Out1> Out2>
104 return out_handle.
put( std::make_unique<Out1>( std::forward<Out2>( out ) ) );
107 template <
typename Out1, std::convertible_to<Out1> Out2>
109 return out_handle.put( std::forward<Out2>( out ) );
112 template <
template <
typename>
class Handle,
typename Out,
typename Value>
114 return out_handle.
put( std::forward<Value>( out ) );
118 template <
typename OutHandle,
typename OptOut>
119 requires( is_optional<OptOut> )
120 void put(
const OutHandle& out_handle, OptOut&& out ) {
121 if ( out )
put( out_handle, *std::forward<OptOut>( out ) );
131 template <
typename Container>
134 template <
typename Container,
typename Value>
135 auto operator()( Container& c, Value&& v )
const ->
decltype( c.push_back( v ) ) {
136 return c.push_back( std::forward<Value>( v ) );
139 template <
typename Container,
typename Value>
140 auto operator()( Container& c, Value&& v )
const ->
decltype( c.insert( v ) ) {
141 return c.insert( std::forward<Value>( v ) );
145 template <
typename Container,
typename Value>
146 requires( std::is_pointer_v<typename Container::value_type> &&
147 std::is_convertible_v<Value, c_remove_ptr_t<Container>> )
148 auto operator()( Container& c, Value&& v )
const {
157 template <
typename In>
158 requires( !std::is_pointer_v<In> )
159 const In&
operator()(
const In& in )
const {
163 template <
typename In>
164 requires( !std::is_pointer_v<std::decay_t<In>> )
165 In
operator()( In&& in )
const {
166 return std::forward<In>( in );
169 template <
typename In>
171 assert( in !=
nullptr );
179 template <
typename T>
180 constexpr static bool is_gaudi_range_v =
false;
182 template <
typename T>
183 constexpr static bool is_gaudi_range_v<Gaudi::Range_<T>> =
true;
185 template <
typename T>
186 constexpr static bool is_gaudi_range_v<Gaudi::NamedRange_<T>> =
true;
188 template <
typename T>
189 constexpr static bool is_gaudi_range_v<std::optional<Gaudi::NamedRange_<T>>> =
true;
191 template <
typename In>
193 template <
template <
typename>
class Handle, std::convertible_to<In> I>
197 template <
template <
typename>
class Handle,
typename I>
201 template <
template <
typename>
class Handle,
typename I>
205 template <
template <
typename>
class Handle,
typename I>
209 template <
template <
typename>
class Handle,
typename I>
210 requires( std::is_convertible_v<I*, In> )
211 auto operator()(
const Handle<I>& h ) -> In {
212 return h.getIfExists();
216 template <
typename Iterator>
218 using traits = std::iterator_traits<Iterator>;
222 using iterator_category [[maybe_unused]] =
typename traits::iterator_category;
223 using difference_type [[maybe_unused]] =
typename traits::difference_type;
225 using value_type [[maybe_unused]] = std::remove_reference_t<reference>;
226 using pointer [[maybe_unused]] = std::add_pointer_t<value_type>;
253 requires std::bidirectional_iterator<Iterator>
262 requires std::random_access_iterator<Iterator>
268 requires std::random_access_iterator<Iterator>
274 requires std::random_access_iterator<Iterator>
280 requires std::random_access_iterator<Iterator>
286 requires std::random_access_iterator<Iterator>
288 return m_iter - other.m_iter;
291 requires std::random_access_iterator<Iterator>
299 template <
typename Container>
301 static constexpr bool is_pointer = std::is_pointer_v<Container>;
302 static constexpr bool is_range = details2::is_gaudi_range_v<Container>;
303 template <
typename C>
307 using ptr_t = std::add_pointer_t<val_t>;
311 constexpr static decltype( auto )
wrap( ContainerVector::const_reference t ) {
318 constexpr static auto wrap( ContainerVector::const_iterator i ) {
327 using value_type = std::conditional_t<is_pointer, ptr_t, val_t>;
332 template <
typename T>
333 requires( is_pointer || is_range )
337 template <
typename C = Container>
338 requires( !std::is_pointer_v<C> && !details2::is_gaudi_range_v<C> )
343 template <
typename C = Container>
344 requires( !std::is_pointer_v<C> && !details2::is_gaudi_range_v<C> )
356 template <
template <
typename>
class Handle,
typename I>
362 template <
typename Algorithm>
365 [ptr = &
handles, parent]( auto& self_ ) {
368 ptr->reserve( self.value().size() );
369 std::ranges::transform( self.value(), std::back_inserter( *ptr ),
370 [&](
const auto& location ) -> Handle<I> {
371 return { location, parent };
384 template <
typename Algorithm>
386 :
m_payload{
std::make_unique<Payload>( parent, keys ) } {}
389 template <
typename A,
typename K>
391 template <
typename A,
typename Name,
typename Keys>
402 template <
typename Out>
403 void put( Out&& out )
const {
404 auto const n =
size();
405 if ( out.size() != n ) {
407 std::string{ std::source_location::current().function_name() } +
": expected " +
408 std::to_string( n ) +
" containers, got " + std::to_string( out.size() ) +
" instead",
420 template <
typename T>
422 template <
typename T>
425 template <
typename Arg>
430 template <
typename T>
435 template <
typename Arg>
437 template <
typename Arg>
439 template <
typename... Args>
442 template <
typename... T>
445 template <
typename H>
451 template <
typename Vectors>
452 decltype( auto )
getLocations( Vectors
const& vectors,
unsigned int i ) {
454 [i](
auto const&... elems ) ->
decltype(
auto ) {
return *std::array{ &elems.locations()... }.at( i ); },
458 template <
typename F>
461 return std::forward<F>( f )();
470 template <
typename Algo>
477 template <
typename Tr>
480 template <
typename Tr,
typename Default>
484 template <
typename Tr,
typename Default>
485 requires requires {
typename Tr::BaseClass; }
490 template <
typename T,
typename Tr,
template <
typename...>
typename Default>
494 template <
typename T,
typename Tr,
template <
typename...>
typename Default>
499 template <
typename Tr,
template <
typename...>
typename Default>
501 template <
typename T>
504 template <
typename T,
typename Tr,
template <
typename...>
typename Default>
509 template <
typename T,
typename Tr,
template <
typename...>
typename Default>
513 template <
typename T,
typename Tr,
template <
typename...>
typename Default>
518 template <
typename Tr,
template <
typename...>
typename Default>
520 template <
typename T>
523 template <
typename T,
typename Tr,
template <
typename...>
typename Default>
528 template <
typename T>
531 template <
typename T>
535 template <algtool_
interface T>
543 template <
typename T>
550 template <
typename Tr,
typename Default = Gaudi::Algorithm>
556 template <
typename Tr,
typename T>
559 template <
typename Tr,
typename T>
562 template <
typename T>
566 using KeyValue = std::pair<std::string, std::string>;
567 using KeyValues = std::pair<std::string, std::vector<std::string>>;
573 :
value{
std::move( name_ ), { std::move( location_ ) } } {}
578 LocationSpec( std::string name_, std::initializer_list<std::string> locations_ )
583 throw GaudiException(
"Expected a scalar location specification",
"Gaudi::Functional::details::LocationSpec",
591 template <
typename Arg>
599 template <
typename T>
603 template <
typename T>
607 template <
typename Arg>
610 template <
typename... Args>
613 template <
typename... Args>
617 template <
typename First,
typename... Rest>
621 template <
typename... Args>
624 template <
typename Tuple>
628 template <
typename First,
typename... Rest>
632 template <
typename Tuple>
635 template <
typename Tuple,
typename T>
637 template <
typename T,
typename... Elements>
640 template <
typename Tuple,
typename T>
642 template <
typename T,
typename... Elements>
644 ( std::constructible_from<Elements, T> && ... );
646 template <
typename... Args>
648 template <
typename First,
typename... Rest>
651 template <
bool starts_with_event_context,
typename InputSpecTuple>
653 std::conditional_t<starts_with_event_context, InputSpecTuple, std::tuple<>>{};
655 template <
typename Tuple,
typename Spec, std::size_t... I>
656 Tuple
location_specs_tuple( std::initializer_list<Spec> specs, std::index_sequence<I...>,
const char* component ) {
657 if constexpr (
sizeof...( I ) == 1 ) {
658 if ( specs.size() == 0 )
return Tuple{ Spec{} };
660 if ( specs.size() !=
sizeof...( I ) ) {
663 return Tuple{ *std::next( specs.begin(), I )... };
666 template <
typename Tuple>
671 static constexpr auto indices = std::make_index_sequence<std::tuple_size_v<Tuple>>{};
674 requires( std::tuple_size_v<Tuple> == 0 )
677 template <
typename... Specs>
679 requires(
sizeof...( Specs ) > 0 && std::constructible_from<Tuple, Specs...> )
680 :
m_specs{
std::forward<Specs>( specs )... } {}
681 template <
typename... Args>
683 requires(
sizeof...( Args ) > 1 && std::tuple_size_v<Tuple> == 1 && std::constructible_from<
First, Args...> )
686 requires( std::tuple_size_v<Tuple> == 1 && std::constructible_from<First, std::string, std::string> )
689 requires( std::tuple_size_v<Tuple> == 1 && std::constructible_from<First, std::string, std::vector<std::string>> )
706 template <
typename Traits>
708 std::is_base_of_v<Gaudi::details::LegacyAlgorithmAdapter, details::BaseClass_t<Traits>>;
712 template <
typename Handle,
typename Algo>
713 auto get(
const Handle& handle,
const Algo&,
719 template <
typename Algo>
724 template <
template <
typename>
class Handle,
typename In,
typename Algo>
726 return handle.
get( ctx );
729 template <
typename IFace,
typename Algo>
731 return handle.bind( ctx );
734 template <
typename Handle>
735 auto getKey(
const Handle& h ) ->
decltype( h.objKey() ) {
739 template <
template <
typename>
class Handle,
typename T>
741 return h.locations();
744 template <
typename OutputSpec,
typename InputSpec,
typename Traits_>
745 class DataHandleMixin;
747 template <
typename Outputs,
typename Traits_,
typename... Args>
750 template <
typename... Out,
typename... In,
typename Traits_>
751 requires( std::derived_from<BaseClass_t<Traits_>,
Algorithm> && !std::disjunction_v<std::is_void<Out>...> )
755 constexpr static std::size_t
N_in =
sizeof...( In );
756 constexpr static std::size_t
N_out =
sizeof...( Out );
759 template <
typename IArgs,
typename OArgs, std::size_t... I, std::size_t... J>
761 const OArgs& outputs, std::index_sequence<J...> )
769 using InputHandles = std::tuple<details::InputHandle_t<Traits_, In>...>;
780 template <std::
size_t N>
782 template <std::
size_t N>
784 template <std::size_t... I>
791 template <std::size_t... I>
802 requires( N_in == 0 && N_out == 0 )
803 : DataHandleMixin(
std::move( name ), locator,
std::tuple<>{}, InputSpecs::indices, std::tuple<>{},
804 OutputSpecs::indices ) {}
810 InputSpecs::indices,
std::tuple<>{}, OutputSpecs::indices ) {}
816 OutputSpecs::indices ) {}
822 OutputSpecs::indices ) {}
828 InputSpecs::indices, outputs.tuple(), outputs.indices ) {}
832 requires(
N_out != 0 )
833 :
DataHandleMixin(
std::move( name ), locator, inputs.tuple(), inputs.indices, outputs.tuple(),
842 template <std::
size_t N = 0>
848 template <
typename T>
854 template <std::
size_t N = 0>
858 return std::get<input_handle_index<N>>(
m_inputs ).at( n ).key();
868 auto size = [](
const auto& handle ) {
870 return static_cast<unsigned int>( handle.size() );
876 size](
const auto&... handles ) {
return std::array{ size( handles )... }.at( i ); },
894 template <std::
size_t N = 0>
896 requires(
N_out > 0 )
900 template <
typename T>
902 requires(
N_out > 0 )
906 template <std::
size_t N = 0>
910 return std::get<N>(
m_outputs ).at( n ).key();
920 template <
typename Algorithm>
923 [&](
const auto&... handle ) ->
decltype(
auto ) {
return algo(
get( handle, algo, ctx )... ); },
m_inputs );
934 template <
typename InputSpec,
typename Traits_>
940 template <
typename OutHandles,
typename Outputs>
941 void put_results(
const OutHandles& out_handles, Outputs&& outputs ) {
942 [&]<std::size_t... I>( std::index_sequence<I...> ) {
943 (
put( std::get<I>( out_handles ), std::get<I>( std::forward<Outputs>( outputs ) ) ), ... );
944 }( std::make_index_sequence<std::tuple_size_v<std::remove_reference_t<Outputs>>>{} );
947 template <
typename Algorithm,
typename OutHandles = std::tuple<>>
949 requires( std::tuple_size_v<OutHandles> <= 1 )
951 return execute( algo, [&] {
952 if constexpr ( std::tuple_size_v<OutHandles> == 0 ) {
953 algo.invoke( algo, ctx );
955 put( std::get<0>( out_handles ), algo.invoke( algo, ctx ) );
957 return FilterDecision::PASSED;
961 template <
typename Algorithm,
typename OutHandles>
964 put_results( out_handles, algo.invoke( algo, ctx ) );
969 template <
typename Algorithm,
typename OutHandles>
973 [&](
bool passed,
auto&&... data ) {
974 put_results( out_handles, std::forward_as_tuple( std::forward<
decltype( data )>( data )... ) );
977 algo.invoke( algo, ctx ) )
bool PyHelper setProperty(IInterface *p, char *name, char *value)
boost::spirit::classic::position_iterator2< ForwardIterator > Iterator
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
DataObjectHandle.h GaudiKernel/DataObjectHandle.h.
T * put(std::unique_ptr< T > object) const
Register object in transient store.
This class represents an entry point to all the event specific data.
Base class from which all concrete algorithm classes should be derived.
static constexpr bool all_input_locations_are_vectors
unsigned int outputLocationSize() const
std::tuple< details::OutputHandle_t< Traits_, Out >... > OutputHandles
static constexpr bool starts_with_event_context
static constexpr std::size_t N_in
LocationSpec::KeyValue KeyValue
DataHandleMixin(std::string name, ISvcLocator *pSvcLocator, const IArgs &inputs, std::index_sequence< I... >, const OArgs &outputs, std::index_sequence< J... >)
DataHandleMixin(std::string name, ISvcLocator *locator, LegacyInputSpecs const &inputs)
decltype(auto) inputLocation(unsigned int i, unsigned int j) const
decltype(auto) outputLocation() const
DataHandleMixin(std::string name, ISvcLocator *locator, LegacyInputSpecs const &inputs, OutputSpecs const &outputs)
DataHandleMixin(std::string name, ISvcLocator *locator, InputSpecs const &inputs)
TailLocationSpecs_t< In... > LegacyInputSpecTuple
bool isReEntrant() const override
decltype(auto) inputLocation() const
LocationSpecs_t< Out... > OutputSpecTuple
static constexpr std::size_t input_handle_index
DataHandleMixin(std::string name, ISvcLocator *locator, InputSpecs const &inputs, OutputSpecs const &outputs)
static constexpr std::size_t N_input_locations
DataHandleMixin(std::string name, ISvcLocator *locator, OutputSpecs const &outputs)
auto input_location_handles(std::index_sequence< I... >) const
static constexpr std::size_t input_location_offset
static constexpr std::size_t N_out
unsigned int inputLocationSize(unsigned int i) const
static constexpr bool input_locations_are_vectors(std::index_sequence< I... >)
details::LocationSpecs< LegacyInputSpecTuple > LegacyInputSpecs
decltype(auto) inputLocation() const
details::LocationSpecs< InputSpecTuple > InputSpecs
decltype(auto) invoke(const Algorithm &algo, const EventContext &ctx) const
details::LocationSpecs< OutputSpecTuple > OutputSpecs
std::tuple_element_t< input_handle_index< N >, InputHandles > InputLocationHandle
decltype(auto) outputLocation(unsigned int n) const
decltype(auto) inputLocation(unsigned int n) const
unsigned int inputLocationSize() const
std::tuple< details::InputHandle_t< Traits_, In >... > InputHandles
DataHandleMixin(std::string name, ISvcLocator *locator)
LocationSpecs_t< In... > InputSpecTuple
DataHandleMixin(std::string name, ISvcLocator *locator, std::tuple<>={}, std::tuple<>={})
LocationSpec::KeyValues KeyValues
HandleVector(std::tuple< A, K > &&tup)
std::unique_ptr< Payload > m_payload
DataObjID const & at(size_t i) const
HandleVector(Algorithm *parent, std::pair< std::string, std::vector< std::string > > const &keys)
void put(Out &&out) const
std::vector< DataObjID > const & locations() const
HandleVector(std::tuple< A, Name, Keys > &&tup)
vector_of_const_< T > get(EventContext const &) const
std::vector< OutputHandleFor< Tr, Default >::template type< T > > const & handles() const
LocationSpecs(Args &&... args)
LocationSpecs(std::string name, std::string loc)
first_or_empty_t< Tuple > First
LocationSpecs(Tuple specs)
LocationSpecs(std::string name, std::vector< std::string > locs)
LocationSpecs(std::initializer_list< LocationSpec > specs)
auto with_context() const
Tuple const & tuple() const
static constexpr auto indices
LocationSpecs(Specs &&... specs)
LocationSpecs(std::initializer_list< First > specs)
constexpr indirect_iterator & operator+=(difference_type n)
constexpr indirect_iterator operator--(int)
constexpr indirect_iterator & operator++()
constexpr indirect_iterator & operator-=(difference_type n)
constexpr reference operator*() const
constexpr indirect_iterator(Iterator i)
constexpr indirect_iterator operator+(difference_type n) const
constexpr bool operator==(const indirect_iterator &rhs) const
std::iterator_traits< Iterator > traits
constexpr indirect_iterator operator-(difference_type n) const
constexpr difference_type operator-(const indirect_iterator &other) const
constexpr reference operator[](difference_type n) const
indirect_iterator()=default
constexpr indirect_iterator operator++(int)
constexpr indirect_iterator & operator--()
decltype(**m_iter) reference
static constexpr decltype(auto) wrap(ContainerVector::const_reference t)
static constexpr bool is_range
static constexpr auto wrap(ContainerVector::const_iterator i)
static constexpr bool is_pointer
std::add_pointer_t< val_t > ptr_t
void push_back(borrowed_value_t< C > &&)=delete
ContainerVector m_containers
decltype(auto) back() const
std::add_const_t< std::remove_pointer_t< C > > borrowed_value_t
vector_of_const_()=default
void push_back(borrowed_value_t< C > &container)
void push_back(T &&container)
void reserve(size_type size)
typename ContainerVector::size_type size_type
std::vector< std::conditional_t< is_range, std::remove_const_t< val_t >, ptr_t > > ContainerVector
std::conditional_t< is_pointer, ptr_t, val_t > value_type
borrowed_value_t< Container > val_t
decltype(auto) at(size_type i) const
decltype(auto) front() const
Implementation of property with value of concrete type.
Useful class for representation of "sequence" of the objects through the range of valid iterators.
Define general base for Gaudi exception.
virtual const std::string & message() const
error message to be printed
virtual const StatusCode & code() const
StatusCode for Exception.
virtual const std::string & tag() const
name tag for the exception, or exception type
The ISvcLocator is the interface implemented by the Service Factory in the Application Manager to loc...
This class is used for returning status codes from appropriate routines.
constexpr static const auto FAILURE
Gaudi::tagged_bool< class ImmediatelyInvokeHandler_tag > ImmediatelyInvokeHandler
typename Tr::BaseClass BaseClass_t
typename DefaultInputHandle< T >::type DefaultInputHandle_t
StatusCode execute_outputs(const Algorithm &algo, const EventContext &ctx, const OutHandles &out_handles)
typename detail2::InputHandle< T, Tr, detail2::DefaultInputHandle_t >::type InputHandle_t
auto get(const Handle &handle, const Algo &, const EventContext &) -> decltype(details::deref(handle.get()))
decltype(auto) getLocations(Vectors const &vectors, unsigned int i)
typename first_or_empty< Tuple >::type first_or_empty_t
auto getKey(const Handle &h) -> decltype(h.objKey())
constexpr auto empty_input_specs
typename TailLocationSpecs< Args... >::type TailLocationSpecs_t
std::vector< DataObjID > to_DataObjID(const std::vector< std::string > &in)
typename handle_vector_input< Arg >::type handle_vector_input_t
auto put(const DataObjectHandle< Out1 > &out_handle, Out2 &&out)
constexpr bool tuple_elements_are_v
std::tuple< LocationSpec_t< Args >... > LocationSpecs_t
typename detail2::OutputHandle< T, Tr, DataObjectWriteHandle >::type OutputHandle_t
StatusCode execute_single_output(const Algorithm &algo, const EventContext &ctx, const OutHandles &out_handles={})
constexpr bool first_is_event_context_v
constexpr struct Gaudi::Functional::details::deref_t deref
constexpr bool is_handle_vector_input_v
typename LocationSpecFor< std::remove_cvref_t< Arg > >::type LocationSpec_t
typename details2::value_type_of< T >::type remove_optional_t
constexpr bool is_event_context_v
detail2::BaseClass< Tr, Default >::type BaseClass_t
decltype(get_values_helper< Value >(std::make_index_sequence< N >())) RepeatValues_
StatusCode execute_filtered_outputs(const Algorithm &algo, const EventContext &ctx, const OutHandles &out_handles)
auto get_values_helper(std::index_sequence< I... >)
DataHandleMixin< Outputs, type_list< handle_vector_input_t< Args >... >, Traits_ > DataHandleVectorMixin
StatusCode execute(CommonMessagingBase const &alg, F &&f)
void put_results(const OutHandles &out_handles, Outputs &&outputs)
Tuple location_specs_tuple(std::initializer_list< Spec > specs, std::index_sequence< I... >, const char *component)
constexpr bool tuple_elements_constructible_from_v
EventContextHandle(std::tuple< Algo >)
Payload & operator=(Payload const &)=delete
std::vector< Handle< I > > handles
Gaudi::Property< std::vector< DataObjID > > property
Payload(Algorithm *parent, std::pair< std::string, std::vector< std::string > > const &keys)
Payload(Payload &&)=delete
Payload(Payload const &)=delete
Payload & operator=(Payload &&)=delete
LocationSpec::KeyValues type
LocationSpec::KeyValue type
LocationSpec(std::string name_, std::vector< std::string > locations_)
std::pair< std::string, std::string > KeyValue
std::pair< std::string, std::vector< std::string > > KeyValues
LocationSpec(std::string name_, std::initializer_list< std::string > locations_)
LocationSpec(std::string name_, const char *location_)
LocationSpec(std::string name_, std::string location_)
LocationSpecs_t< Rest... > type
const In & operator()(const In *in) const
Tr::template OutputHandle< T > type
HandleVector< OutputHandleFor< Tr, Default >::template type, T > type
typename OutputHandle< remove_optional_t< T >, Tr, Default >::type type
auto operator()(const Handle< std::optional< Gaudi::NamedRange_< I > > > &h) -> In
auto operator()(const Handle< I > &h) -> const In &
auto operator()(const Handle< Gaudi::NamedRange_< I > > &h) -> In
auto operator()(const Handle< Gaudi::Range_< I > > &h) -> In
std::remove_pointer_t< typename Container::value_type > c_remove_ptr_t
auto operator()(Container &c, Value &&v) const -> decltype(c.push_back(v))
auto operator()(Container &c, Value &&v) const -> decltype(c.insert(v))
void operator()(F &&f, Arg &&arg) const
decltype(auto) operator()(F &&f, Arg &&arg) const