简体   繁体   中英

Compiler errors on partial template speciailzation (c++)

I am trying to do a simple partial template specialization, but I get errors on g++4.4.7, g++4.8.5, clang++3.8.0. Whenever I mention compiler(s) error, I mean the output of all of these, as they always agree. I am using C++03, compiling without any option.

The code:

#include <iostream>

template <typename T, typename X, typename G>
struct A {};

template <typename T, typename X>
struct A<T, X, void> { A() : n(1) {} X n; T b; };

template <typename X>
struct A<X, void, void> { A() : n(2) {} X n; };

int main() {
  A<int, float> one;
  A<int> two;
  std::cout << one.n << " | " << two.n << "\n";
  return 0;
}

Question 1: This code fails to compile. The compilers say that A<int, float> and A<int> are wrong as A requires 3 templates parameters. Why?

If I change the original declaration to

template <typename T, typename X = void, typename G = void>
struct A {};

The code compiles and the output is: 1 | 2 1 | 2 .

What happens is that the compiler in a first step matches one and two type to the not specialized A , but then it correctly decides to use the code of the partially specialized class one would expect it to use. But it should not need the defaults.

I then decide to change the last partial specialization switching the first and second parameter:

template <typename X>
struct A<void, X, void> { A() : n(2) {} X n; };

I would expect this to change nothing, but the compilers disagree. The clearest output between the 3 is here reported:

a.cpp:7:40: error: field has incomplete type 'void'
struct A<T, X, void> { A() : n(1) {} X n; T b; };
                                   ^
a.cpp:14:10: note: in instantiation of template class 'A<int, void, void>'    requested here
  A<int> two;
         ^
1 error generated.

Question 2: Why are the compilers considering the two variable an instance of the partial specialization of A that specializes only one argument?

Note that is the "2nd matching", because if I only use 1 default template argument, the compiler will go back to complaining about the fact that 3 template parameters are needed.

Thanks.

Question 1: This code fails to compile. The compilers say that A<int, float> and A<int> are wrong as A requires 3 templates parameters. Why?

Because A requires 3 template parameters. You declared A as:

template <typename T, typename X, typename G>
struct A {};

There is no two- or one-template parameter version of A . There are versions specialized on some of the types being void , but that's still a parameter - not an absence of parameter.

When you add the defaults, then A<int, float> evaluates as A<int, float, void> , which is a valid instantiation - and picks the specialization which sets n to 1.

You're misunderstanding how specialization works. Specialization doesn't change the number of template parameters. It's just a way of adding special functionality depending on what the template parameters end up being.

Question 2: Why are the compilers considering the two variable an instance of the partial specialization of A that specializes only one argument?

We have three choices

template <T, X, G>       struct A; // the primary
template <T, X, void>    struct A; // (1)
template <void, X, void> struct A; // (2)

When we instantiate A<int> , that is the same as A<int, void, void> when we add in the default parameters. That does not match (2) - because that one requires the first parameter to be void and yours is int . (1) is a better match than the primary since it's more specialized. But then, (1) has a member of type X and in this case X is deduced as void (from the default parameter), and that's not allowed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM