c++c++11templatesvariadicpartial-ordering

C++ template: cannot match the last template in variadic class template


I'm learning C++11 variadic template and created a template struct to calculate the max number of a given list and tried:

#include <iostream>
#include <type_traits>

template <int a, int b, int... cs>
struct max: std::integral_constant<int, (a>b? max<a, cs...>::value: max<b, cs...>::value)> {};
template <int a, int b>
struct max<a, b>: std::integral_constant<int, (a>b? max<a>::value: max<b>::value)> {};
template <int a>
struct max<a>: std::integral_constant<int, a> {};

int main() {
  std::cout << max<2,1,5,7>::value << std::endl;
  return 0;
}

but g++ complains:

test.cc:7:58: error: wrong number of template arguments (1, should be at least 2)
 struct max<a, b>: std::integral_constant<int, (a>b? max<a>::value : max<b>::value)> {};

test.cc:9:13: error: wrong number of template arguments (1, should be at least 2)
 struct max<a>: std::integral_constant<int, a> {};

I can make it run by adding a simple declaration ahead:

template <int...>
struct max;

and change the first template above to:

template <int a, int b, int... cs>
struct max<a, b, cs...>: ...

I referred to cppreference: https://en.cppreference.com/w/cpp/language/partial_specialization#Partial_ordering but I cannot find any useful explanation for my case.

The problem may come from the last template (max<a>) with only one template parameter, which is not a specialized version of the primary one.

So my question is:

Why max<a> cannot be matched? Is there any rules or standards dealing with this?

=================================================================

okay, I found the C++ standards (Document No. N4659) that says:

[ Note: Partial specializations of class templates are found by looking up the primary class template and then considering all partial specializations of that template. If a using-declaration names a class template, partial specializations introduced after the using-declaration are effectively visible because the primary template is visible (17.5.5). — end note ]

So I think any partial specialized template that does not specialize from the base/primary one is considered to be an error, even though sometimes we can generate some non-specialized forms of expression from normal ones.


Solution

  • When you define a class template as:

    template <int a, int b, int... cs> struct max { ... };
    

    The following is a valid specialization.

    template <int a, int b> struct max<a, b> { ... };
    

    However, the following is not.

    template <int a> struct max<a> { ... };
    

    since the base class template requires at least two template parameters.