Yes, you can deduce the return type of the callable type F
using function traits.
Remove typename R
from the template parameter list, move typename F
to the beginning of the template parameter list, and replace all occurrences of R
with typename function_traits<F>::return_type
. We can use a template using
declaration to help us:
template <typename F>
using Ret = typename function_traits<F>::return_type;
template <typename T>
using EnableIfVoid = typename std::enable_if<std::is_void<T>::value, T>::type;
template <typename T>
using EnableIfNotVoid = typename std::enable_if<! std::is_void<T>::value, T>::type;
// void return
template<typename F, typename = EnableIfVoid<Ret<F>>, typename T, typename... A>
static std::function<void()> Weak(F func, const std::shared_ptr<T>& obj, A&&... args)
{
return std::bind(Wrapper<void>(), std::weak_ptr<T>(obj),
std::function<void()>(std::bind(func, obj.get(),
std::forward<Args>(args)...)));
}
// non void return with explicit default
template<typename F, typename = EnableIfNotVoid<Ret<F>>, typename T, typename... A>
static std::function<Ret<F>()> Weak(Ret<F> d, F func, const std::shared_ptr<T>& obj, A&&... args)
{
return std::bind(Wrapper<Ret<F>>(), std::weak_ptr<T>(obj),
std::function<Ret<F>()>(std::bind(func, obj.get(),
std::forward<Args>(args)...)), d);
}
// non void return with implicit default
template<typename F, typename = EnableIfNotVoid<Ret<F>>, typename T, typename... A>
static std::function<Ret<F>()> Weak(F func, const std::shared_ptr<T>& obj, A&&... args)
{
return Weak(Ret<F>(), func, obj, std::forward<Args>(args)...);
}
I had to make your D
parameter a function argument instead of a template parameter, otherwise you would've been forced to write Bind::Weak<decltype(f), 42>(f, obj)
.
(a) Bind::Weak(func, obj, args...)
(b) Bind::Weak(true, func, obj, args...)
(c) Bind::Weak(42, func, obj, args...)
[I feel you should be able to do this without having to call bind
twice, but I don't know enough about what you are trying to do.]