I'm trying to define a function template<typename T> zero() and specialize it to various cases.
zero<T>() should return
static T::zero()if that exists.- else
static_cast<T>(0)if that is defined.
So far so good, as implemented below.
Now I want to extend the template in a sensible way to any T that is implicitly convertible to a type of the form std::function<Y(X...)>, and should return the corresponding zero-returning function [](X...){return zero<Y>();}
What would be the best way to do this?
namespace hidden {
// tag dispatching
template<int r>
struct rank : rank<r - 1> {};
template<>
struct rank<0> {};
template<typename T>
auto zero(rank<2>) -> decltype(T::zero()) {
return T::zero();
}
template<typename T>
auto zero(rank<1>) -> decltype(static_cast<T>(0)) {
return static_cast<T>(0);
}
// This is where I need help
template<typename T>
auto zero(rank<0>) -> std::enable_if_t</* T is implicitly convertible to std::function<Y(X...)> */,T> {
using Y = // the type returned when an instance of T is invoked
return []() {
return zero<Y>();
};
}
}
template<typename T>
auto zero() { return hidden::zero<T>(rank<10>{}); }
Edit:
I've resorted for now to repeating the following with concrete signature for each expected signature:
template<typename T>
auto zero(rank<0>)
-> std::enable_if_t<std::is_assignable<std::function<double(double)>, T>::value
, std::function<double(double)>> {
using Y = double;
return []() {
return zero<Y>();
};
}
but I'm hoping it's possible to replace the copy-pasting with template magic.