Martin
Martin

Reputation: 9359

Partial specialization of a template

Consider:

template <typename Function, typename ...Args>
auto wrapper(Function&& f, Args&&... args) -> decltype(f(args...)) {
//...
}

Is there a way to partially specialize the above template for all the cases where decltype(f(args...)) is a pointer?

EDIT:
I think it can be done with an template helper class which takes decltype(f(args...)) as template argument, and specialize the helper class. If you know better solutions let me know.

Upvotes: 6

Views: 213

Answers (2)

Luc Danton
Luc Danton

Reputation: 35439

An SFINAE-based solution:

#include <type_traits>

template<
    typename Functor
    , typename... Args
    , typename Result = decltype(std::declval<Functor&>()(std::declval<Args>()...))
    , typename std::enable_if<
        std::is_pointer<Result>::value
        , int
    >::type = 0
>
Result wrapper(Functor&& functor, Args&&... args)
{ /* ... */ }

template<
    typename Functor
    , typename... Args
    , typename Result = decltype(std::declval<Functor&>()(std::declval<Args>()...))
    , typename std::enable_if<
        !std::is_pointer<Result>::value
        , int
    >::type = 0
>
Result wrapper(Functor&& functor, Args&&... args)
{ /* ... */ }

You can adapt the test (here, std::is_pointer<Result>) to your needs.

Upvotes: 3

pmr
pmr

Reputation: 59811

As you see the return type is not a template argument or part of the arguments, so you cannot overload nor specialize. Dispatching on a helper is your best option.

#include <type_traits>

template<typename Func, typename... Args>
void func_impl(Func&& f, Args&&... args, std::true_type) 
-> decltype(func_impl(std::forward<Args>(args)...)) 
{ }

template<typename Func, typename... Args>
void func_impl(Func&& f, Args&&... args, std::false_type) 
-> decltype(func_impl(std::forward<Args>(args)...)) 
{ }

template<typename Func, typename... Args>
auto func(Func&& f, Args&&... args) 
  -> decltype(func_impl(std::forward<Func>(f), std::forward<Args>(args)...))
{ return func_impl(std::forward<Func>(f), std::forward<Args>(args)..., 
                   std::is_pointer<decltype(f(std::forward<Args>(args)...))>::type); }

It seems a little odd to me to take the function by rvalue reference though and you also omit the forwarding in your original example.

Another possible solution could be a template default argument and overload on that. But that wouldn't work well with the argument list.

Upvotes: 1

Related Questions