Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

gcc vs clang behavior on partial specialization with variadic arguments plus extra argument of same type

The following code:

#include <cstddef>

template <size_t N,
          typename T,
          T first,
          T... rest>
struct A {
};

template<typename T,
         T... args>
struct A<0, T, args...> {
};

int main () {
    A<0, int, 1> a0;
    A<2, int, 1, 2> a2;
    return 0;
}

...does not compile with g++ (version 5.1.0 and 5.3.0) due to:

error: partial specialization is not more specialized than the primary template because it replaces multiple parameters with a pack expansion

...but compiles with clang.

Is it allowed to declare such partial specializations?

Side note: Actually, the specialization is dangerous since A<0, int> fails to compile with both compiler (wrong number of template arguments).

like image 506
Holt Avatar asked Mar 29 '16 19:03

Holt


1 Answers

gcc is correct, the code is ill-formed because the specialization isn't actually more specialized.


The rule, from [temp.class.spec] is (as a result of DR 1495, h/t T.C. for the link):

Within the argument list of a class template partial specialization, the following restrictions apply: [...] The specialization shall be more specialized than the primary template (14.5.5.2).

In order to determine that, we would rewrite the two as synthesized function templates:

template <size_t N, class T, T first, T... rest>
void __f(A<N, T, first, rest...> );  // primary

template <class T, T... args>
void __f(A<0, T, args...> );         // specialization

and then go through the partial ordering rules. That, in turn, involves synthesizing new types/values for each of the template parameters and seeing if deduction can succeed in either direction.

Definitely, the deduction of the specialization fails with the primary (due to N vs 0). In the other direction, from [temp.deduct.partial]:

If A was transformed from a function parameter pack and P is not a parameter pack, type deduction fails.

Since we're trying to deduce T first against a pack, deduction fails in this direction as well. This means that neither of the synthesized function templates is more specialized than other, which in turn means that the class template specialization is not more specialized than the primary template. Hence, gcc would be correct to reject.

like image 85
Barry Avatar answered Oct 08 '22 09:10

Barry