I had a similar case when implementing Cache with the Fetch function. Sort of:
template<class KEY, class VALUE, class FetchFunctor> class Cache { ... };
Phase 1
I wanted to save the user to indicate the type of his / her FetchFunctor and without the C ++ 17 class template argument argument, I went for the createCahce helper method, like this:
// [1] template<class KEY, class VALUE, class FetchFunctor> auto createCache(FetchFunctor fetchFunctor) { return Cache<KEY, VALUE, FetchFunctor>(fetchFunctor); }
Thus, creating a cache is quite simple, for example:
auto cache = createCache<int, int>([](int i){return i+3;});
Phase 2
It would be much better to allow the user to create a cache without having to provide the Key and Value types of the cache and deduce them as provided by the FetchFunctor . Therefore, I added an additional createCache method :
// [2] template<class FetchFunctor> auto createCache(FetchFunctor fetchFunctor) { // function_traits is a namespace where I 'hide' the // traits structs for result type and arguments type deduction using f = function_traits::traits<decltype(fetchFunctor)>; using KEY = typename f::template arg<0>::type; using VALUE = typename f::result_type; return Cache<KEY, VALUE, FetchFunctor>(fetchFunctor); }
Now creating a cache is even easier:
auto cache = createCache([](int i){return i+3;});
But can both the createCache methods above live together?
Fortunately, yes.
- If the user provides the arguments to the Key, Value template, then the first one is the only one.
- If the user does not provide template arguments, the compiler treats the second as "more specialized" and prefers it.
Thus, we can support all of the cases below:
// [a] auto cache = createCache([](int i){return i+3;}); // compiler deduces Key, Value to be: int, int - using the 2nd createCache // [b] auto cache = createCache<int, int>([](auto i){return i+3;}); // we have a generic lambda so we provide Key and Value - using the 1st createCache // [c] auto cache = createCache<string, string>( [](const char* s){return string(s) + '!';} ); // we want different Key and/or Value than would be deduced - we use 1st createCache
Yet...
The following commands will not compile:
auto cache = createCache([](auto i){return i+3;});
But this should not bother us ... you can provide the key and value, as in [b] above.
the code:
http://coliru.stacked-crooked.com/a/e19151a5c245d7c3