0
votes

https://stackoverflow.com/a/22487113/4416169 in the following answer we can see the code in scrutiny:

#include <iostream>
#include <type_traits>

template <typename T, T N, typename = void > 
struct X {
  static const bool isZero = false;
};

template <typename T, T N>
struct X < T, N, typename std::enable_if<N == 0>::type > {
  static const bool isZero = true;
};

int main(int argc, char* argv[]) {
    std::cout << X <int, 0>::isZero << std::endl;
    std::cout << X <int, 1>::isZero << std::endl;
    return 0;
}

https://stackoverflow.com/a/35652391/4416169 here we can see how templates are chosen:

Choosing a template specialization happens in five steps:

  1. Take the primary template declaration.
  2. Fill in user-specified template arguments.
  3. Function templates only: Deduce additional template arguments.
  4. Use defaults for remaining template arguments.
  5. Use the partial ordering algorithm (C++14 14.5.6.2) to choose the best-matching specialization.

firstly, im aware that SFINAE will take care of excluding the struct with the std::enable_if<N==0> as it will not have the ::type defined (making it compile to error, but of course substitution failure is NOT an ERROR, just exclude the template from the final specialization options, so beautiful) when N != 0. Since N!=0 always results in the formerly defined template being chosen(the unspecialized one), I wonder why is it that N=0 chooses the latterly defined template(the specialized one) over the former. Thus following these steps we can further scrutinize(in the case of T=int and N=0):

  1. template<typename T, T N, typename = void>
  2. T is int, N is 0; template<int,0,(unnamed-type)>
  3. do nothing we are not a function.
  4. (unnamed-type) is void; template<int,0,void>
  5. this is explained here: https://stackoverflow.com/a/17008568/4416169

We know now that when we try to access X<int,0>::isZero there are two options, the one with the default template type set to void by default, and the one where that same template type is set to void but not by default but explicitly.

  • Does the compiler always prefer the template(out of all available template specializations) with the least arguments?

  • Moreover and expanding: would this mean that the template with the least actual arguments is chosen over the one with the same amount of explicit(explicit as in non-defaulted or obligatory) arguments but that has the remainder set to a default value?

To be even more clear:

template<typename T, T N, typename C = void>
struct defTempArgStruct {
    static constexpr unsigned int value = 0;
};

template<typename T, T N>
struct  defTempArgStruct<T,N>
{
    static constexpr unsigned int value = 99;
};


int main()
{
    std::cout << defTempArgStruct<int, 2>::value << std::endl;
}

why does that code choose the second specialized template(<typename T, T N>),displaying 99, over the first? And why does it choose the first, displaying 0, when the second, specialized, one changes to be:

template<typename T, T N>
struct  defTempArgStruct<T,N,float>
{
    static constexpr unsigned int value = 99;
};

very confusing.

PLEASE be eager to correct anything anywhere that im getting wrong!

1

1 Answers

2
votes

A viable partial specialization is always preferred over the primary template:

[temp.class.spec.match]/1 When a class template is used in a context that requires an instantiation of the class, it is necessary to determine whether the instantiation is to be generated using the primary template or one of the partial specializations. This is done by matching the template arguments of the class template specialization with the template argument lists of the partial specializations.

(1.1) — If exactly one matching specialization is found, the instantiation is generated from that specialization.
(1.2) — If more than one matching specialization is found, the partial order rules (17.5.5.2) are used to determine whether one of the specializations is more specialized than the others. If none of the specializations is more specialized than all of the other matching specializations, then the use of the class template is ambiguous and the program is ill-formed.
(1.3) — If no matches are found, the instantiation is generated from the primary template.