How does partial specialization work for non type template parameters?

Viewed 66

I would like to understand how the standard determines which partial specialization to pick below. For example, does it have anything to do with number of template parameters in the specialization? Otherwise, how does it determine the "best-fit" match?

#include <cstdint>

template <int ...I>
struct Vector;

template <typename T>
struct Transform;

template <int x, int ...I>
struct Transform<Vector<x,x,I...>> {
   using type = int;
};

template <int ...I>
struct Transform<Vector<I...>> {
   using type = char;
};

int main() {
    static_assert(sizeof(Transform<Vector<1,1,2>>::type) == 4);
}
1 Answers

No, it works differently. It has some dominance functionality. If a specialization is clearly further specializes another then it is chosen but otherwise it is ambiguous. The method isn't too intelligent and is meant to deal with simple cases. In any complicated case you'd better make sure there is no ambiguity at all.

For instance, neither

template <int x, int y, int ...I>
struct Transform<Vector<x, y, y, y, I...>> {
     using type = short;
};

nor

template <int x, int y, int ...I>
struct Transform<Vector<x, y, y, x, I...>> {
     using type = short;
};

is a further specialization of the two x case

template <int x, int ...I>
struct Transform<Vector<x, x, I...>> {
   using type = int;
};

So if you were to declare either one then Transform<Vector<1,1,1,1>> would be ambiguous. To resolve it you'd have to define the specialization for Vector<x, x, x, x, I...> or restrict the previous ones.

However, if instead of the above you were to define

template <int x, int y, int ...I>
struct Transform<Vector<x, x, y, y, I...>> {
     using type = short;
};

Then it would be the chosen form for Transform<Vector<1,1,1,1>> - as this clearly further specializes the two x case.

Related