Pregunta

Following code gives compiler error which is expected (Demo):

  1 template<bool> struct Range;
  2 
  3 template<int value, typename = Range<true> > struct Unique;
  4 template<int value> struct Unique<value, Range<(value > 1)> > { typedef char type[1]; };
  5 template<int value> struct Unique<value, Range<(value > 2)> > { typedef char type[2]; };
  6 
  7 Unique<3>::type o1;
  8 Unique<3>::type o2;

Now, if I swap line-5 and line-7. Then there is NO compiler error !! Demo.

  5 Unique<3>::type o1;

  7 template<int value> struct Unique<value, Range<(value > 2)> > { typedef char type[2]; };

For o1, it's understandable to have no error, because specialization for (value > 2) is not yet visible. But why there no error for o2 also, which sees 2 matching specializations !?
My guess is that, compiler should be choosing the Unique<3>::type with some arbitrary name when it encounters for the 1st time and then replacing Unique<3>::type everywhere with that name.

Is this a compilation bug or C++ bug or C++ "feature" ?

¿Fue útil?

Solución

In 14.5.5.1 Matching of class template partial specializations, there is

If more than one matching specialization is found, the partial order rules (14.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.

However, this would only apply to your first case where there are two specializations visible, and I am not sure yet if those two specializations are valid in themselves.

In your second case, however, before the second specialization is reached, the template-id Unique<3> already exists, for which (thanks n.m., Matthieu M., James Kanze) the first specialization is already instantiated:

14.5.5 Class template partial specializations

A partial specialization shall be declared before the first use of a class template specialization that would make use of the partial specialization as the result of an implicit or explicit instantiation in every translation unit in which such a use occurs; no diagnostic is required.

And in 14.5.5, Item 8

Within the argument list of a class template partial specialization, the following restrictions apply:

— A partially specialized non-type argument expression shall not involve a template parameter of the partial specialization except when the argument expression is a simple identifier. [ >Example:

template <int I, int J> struct A {};

template <int I> struct A<I+5, I*2> {}; // error

template <int I, int J> struct B {};

template <int I> struct B<I, I> {}; // OK

—end example ]

So it seems that non-type arguments do not participate in specialization creation, if not used as a simple identifier (thus Range<(value > 2)> would be wrong).

So it seems your code is not well-formed.


Not directly related but still interesting in this regard:

14.7.3 Explicit specialization

The placement of explicit specialization declarations for function templates, class templates, member functions of class templates, static data members of class templates, member classes of class templates, member class templates of class templates, member function templates of class templates, member functions of member templates of class templates, member functions of member templates of non-template classes, member function templates of member classes of class templates, etc., and the placement of partial specialization declarations of class templates, member class templates of non-template classes, member class templates of class templates, etc., can affect whether a program is well-formed according to the relative positioning of the explicit specialization declarations and their points of instantiation in the translation unit as specified above and below. When writing a specialization, be careful about its location; or to make it compile will be such a trial as to kindle its self-immolation.

Otros consejos

A template is instantiated the first time it is needed (in the translation unit), not each time.

o1 doesn't see the second specialization because of this:

14.5.5/1 A partial specialization shall be declared before the first use of a class template specialization that would make use of the partial specialization as the result of an implicit or explicit instantiation in every translation unit in which such a use occurs; no diagnostic is required.

In the second example, the second specialization would be used in the instantiation of Unique<3> if it were seen before the declaration of o1. Since this rule is violated, the program is broken, and the compiler is allowed to be silent about it.

o2 doesn't see the second specialization because it doesn't see any specialization at all. Its class is instantiated once, at the point of o1 declaration.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top