So yet another question in this saga. Guillaume Racicot has been good enough to provide me with yet another workaround so this is the code I'll be basing this question off of:
struct vec
{
double x;
double y;
double z;
};
namespace details
{
template <typename T>
using subscript_function = double(*)(const T&);
template <typename T>
constexpr double X(const T& param) { return param.x; }
template <typename T>
constexpr double Y(const T& param) { return param.y; }
template <typename T>
constexpr double Z(const T& param) { return param.z; }
}
template <typename T, typename = void>
constexpr details::subscript_function<T> my_temp[] = { &details::X<T>, &details::Y<T> };
template <typename T>
constexpr details::subscript_function<T> my_temp<T, enable_if_t<is_floating_point_v<decltype(details::X(T()))>, T>>[] = { &details::X<T>, &details::Y<T>, &details::Z<T> };
int main() {
vec foo = { 1.0, 2.0, 3.0 };
for(const auto i : my_temp<decltype(foo)>) {
cout << (*i)(foo) << endl;
}
}
The problem seems to arise in my specialization when I return something other than void. In the code above for example, enable_if_t<is_floating_point_v<decltype(details::X(T()))>, T> prevents specialization, while simply removing the last argument and allowing enable_if to return void allows specialization.
I think this points to my misunderstanding of what is really happening here. Why must the specialized type always be void for this to work?
Not sure to understand what you don't understand but...
If you write
you have a first, main, template variable with two templates: a type and a type with a default (
void).The second template variable is enabled when
std::enable_if_tisvoid.What's happen when you write
?
The compiler:
1) find
my_temp<decltype(foo)>that has a single template parameter2) look for a matching
my_temptemplate variable3) find only a
my_tempwith two template parameters but the second has a default, so4) decide that
my_temp<decltype(foo)>can be onlymy_temp<decltype(foo), void>(ormy_temp<vec, void>, if you prefer)5) see that the main
my_tempmatches6) see that the
my_tempspecialization doesn't matches becauseis
T(that isvec), so could match onlymy_temp<vec, vec>that is different frommy_temp<vec, void>.7) choose the only template variable available: the main one.
If you want that the specialization is enabled by
you should use
Tas default for second template type in the main template variable.
Off Topic suggestion: better use
std::declvalinside thestd::is_floating_point_vtest; I suggest