10

What is the procedure of comparing the class template specializations? The standard is not detailed on this point (or I am missing the right place).
My question has NOTHING TO DO with deciding what specialization to use during the instantiation. Please, do not comment on that. The question is about comparing the specializations with each other to decide if particular specialization is already defined or not yet.

Consider this sample code:

template <class x1, class x2>
struct CoreTemplate { };

template <class x1, class x2>
struct CoreTemplate<x1*, x2*> { int spec; CoreTemplate() { spec = 1; } };

template <class x1, class x2>
struct CoreTemplate<x2*, x1*> { int spec; CoreTemplate() { spec = 2; } };

int main(int argc, char* argv[])
{
    CoreTemplate<int*, int*> qq;
    printf("var=%d.\r\n", qq.spec);
}

When I try to compile this code with MSVC, I get an error for the instantiation attempt inside the main function:

cpptest1.cxx(15) : error C2752: 'CoreTemplate<x1,x2>' : more than one partial specialization matches the template argument list

For me it would be more logical to issue an error for an attempt to declare identical template specializations. I do not see any difference between the specializations above.

So, does anybody know rules of comparing template specializations? Articles, links, books, etc will also help.

iammilind
  • 68,093
  • 33
  • 169
  • 336
Kirill Kobelev
  • 10,252
  • 6
  • 30
  • 51

3 Answers3

5

The standard is specific in stating that this only happens when you attempt to instantiate the template (§14.5.4.1/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. [emphasis added]

Unfortunately, the rest of your question can't be answered without discussing how to decide which specialization to use during instantiation. Here's the text from the standard (continuing from the excerpt above):

This is done by matching the template arguments of the class template specialization with the template argument lists of the partial specializations.

  • If exactly one matching specialization is found, the instantiation is generated from that specialization.
  • If more than one matching specialization is found, the partial order rules (14.5.4.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.

So, it never even attempts to compare the templates directly to each other at all. Rather, it attempts to find a specialization that will match the arguments given. If more than one matches, it attempts to pick the most specialized one based on the partial ordering rules. If neither is more specialized than the other, then the instantiation is ambiguous, and compilation fails.

Now, it's certainly true that neither of these specializations could ever be used, since there would always be ambiguity -- if either matches, the other obviously matches equally well. There's simply no requirement for the compiler to detect or diagnose that though. In this exact case (essentially identical specializations) that would probably be easy, but there are almost certainly other cases where it would be much more difficult, so (apparently) the committee decided the compiler didn't even have to try.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • 2
    I think this all comes down to the one definition rule. There can only be one definition of a template, and a partial specialization is a template. So, we're really left with the question of whether two specializations are considered to be the same template, and I can't find anything in the standard that clearly defines that. By studying the behavior of g++, it considers two specializations to be the same template if the template argument lists are the same, while ignoring the specific names. – Vaughn Cato Jun 21 '12 at 07:08
  • Thanks for the reasonable comment. – Kirill Kobelev Jun 21 '12 at 07:10
  • This is not completely true. The compiler needs to compare the partial specialization argument lists. Think about out of line definitions of member functions of the partial specializations. The compiler needs to associate the definition to one of them. – Johannes Schaub - litb Jun 21 '12 at 19:21
1

Ah, but they are not the same because they do not use the same parameters. Using clang and your original example:

#include <cstdio>

template <class x1, class x2>
struct CoreTemplate { };

template <class x1, class x2>
struct CoreTemplate<x1*, x2*> { int spec; CoreTemplate() { spec = 1; } };
// note: partial specialization matches [with x1 = int, x2 = int]

template <class x1, class x2>
struct CoreTemplate<x2*, x1*> { int spec; CoreTemplate() { spec = 2; } };
// note: partial specialization matches [with x1 = int, x2 = int]

int main()
{
    CoreTemplate<int*, int*> qq;
    // error: ambiguous partial specializations of 'CoreTemplate<int *, int *>'
    std::printf("var=%d.\r\n", qq.spec);
}

However if we tweak the partial specializations so that they exactly match:

template <class x1, class x2>
struct Core { };

template <class x1>
struct Core<x1*, x1*> { int spec; Core() { spec = 1; } };
// note: previous definition is here

template <class x1>
struct Core<x1*, x1*> { int spec; Core() { spec = 2; } };
// error: redefinition of 'Core<type-parameter-0-0 *, type-parameter-0-0 *>'

Therefore, it just seems to be a quality of implementation issue. A compiler could emit a warning for the first case, but it might be resource consuming in the general case or it may just be that nobody expressed the need so far.

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
0

For me it would be more logical to issue an error for an attempt to declare identical template specializations.

That would not happen, because CoreTemplate<int*, double*> and CoreTemplate<double*, int*> will generate different types.

Below is my guess:
Compiler may not do the extra sanity/common-sense checks for template bodies.
Once you instantiate a template, at that time compiler looks up for the matching type and picks up the best one. If it doesn't match only one, then it gives compiler error either for no-match or multiple-match.

For example:

template<typename T>
void foo ()
{
  T::x();
}

int main ()
{
}

Would compile fine, even though we know that in whole C++ program there is not a single function name x(). Compiler will give error only when you try instantiating the foo<T>.

Also if you twist your example a bit by putting main() between two specializations, it will compile perfectly fine.

iammilind
  • 68,093
  • 33
  • 169
  • 336
  • Not really. If I put second specialization into the code twice, I immediately get: `cpptest1.cxx(14) : error C2953: 'CoreTemplate' : class template has already been defined`. Besides that the language allows implementing methods of the specialization outside of the definition. From the method header compiler has to understand to what specialization this method belongs. – Kirill Kobelev Jun 21 '12 at 06:47
  • The twist is cheating though, the very nature of C (and C++) is to only look up declarations that were previously declared, so *of course* it works, but it is surprising nonetheless. – Matthieu M. Jun 21 '12 at 06:48
  • @MatthieuM., the terminology behind the 'twist' is that, you can very well include both the specializations separately in 2 different header files and use them in different .cpp files. Everything will always compile fine. The problem will come only when both are visible to any instantiation. – iammilind Jun 21 '12 at 06:51
  • @KirillKobelev, repeating the same class body will definitely give error. That is equivalent to including a single header file multiple times without include guards. :) Here both specializations are different and they both can co-exist, as I have shown in example. – iammilind Jun 21 '12 at 06:54
  • @iammilind: I don't think you meant terminology (which is about explaining semantics). Anyway I agree with you that it may occur in the wild, and will probably lead to a violation of ODR. – Matthieu M. Jun 21 '12 at 07:58