Defined in header <memoized_invoke.hh>
template< typename F >
memoized_invoke( F ) -> memoized_invoke< single_threaded, F >; // (1)
template< typename F, typename... Args >
requires ( sizeof...( Args ) > 0 && std::is_invocable_v< F, Args... > )
memoized_invoke( F, Args... )
-> memoized_invoke< single_threaded, F, std::decay_t< Args >... >; // (2)
These let you write the class name without any template arguments:
memoized_invoke a( []{ return 1; } ); // (1) -> <single_threaded, lambda>
memoized_invoke b( &add, 3, 4 ); // (2) -> <single_threaded, int(*)(int,int), int, int>
memoized_invoke c( &Widget::area, &w, 2.0 ); // (2) -> <single_threaded, ..., Widget*, double>
1) Nullary callable
Deduces memoized_invoke<single_threaded, F> — no Args. Matches the nullary constructor.
2) Callable with arguments
Deduces memoized_invoke<single_threaded, F, std::decay_t<Args>...>. The argument types are decayed — const, references and array-to-pointer are stripped, so memoized_invoke g( f, std::string("x") ) stores std::string, not std::string const&. The requires clause keeps the guide from being considered when F is not invocable with the given arguments (so guide (1) is not shadowed for a nullary F passed extra tokens that are not really arguments).
Both guides always pick single_threaded
A deduction guide has no way to receive the policy — it is not a function you pass arguments to. So CTAD is single_threaded-only by construction. For lock_free (or any other policy) use make_memoized:
auto d = make_memoized<lock_free>( &connect );
or name the full specialisation:
memoized_invoke<lock_free, decltype(&connect)> e( &connect );
Notes
CTAD picks up the guides only for the class-name form (memoized_invoke x( … )). memoized_invoke<…> x( … ) with any explicit argument list bypasses them entirely and uses the constructors directly.
Example
#include <memoized_invoke.hh>
#include <string>
#include <type_traits>
using fedem::utility::memoized_invoke;
using fedem::utility::single_threaded;
int len(std::string const& s) { return static_cast<int>(s.size()); }
int main()
{
memoized_invoke co( &len, std::string("hello") );
static_assert(
std::is_same_v<
decltype(co),
memoized_invoke<single_threaded, int(*)(std::string const&), std::string>
> );
return co() == 5 ? 0 : 1;
}
See also
- make_memoized — the non-
single_threadedpath. - memoizedinvoke::memoizedinvoke — the constructors the guides feed.

