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 decayedconst, 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