Why is SFINAE getting confused when changing the place of specialization of a class template? Is this a C ++ bug?

The following code gives the compiler error that 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 change line-5 and line-7. Then there is a compiler error NO ! Demo

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

For o1 it is clear that there is no error, because the specialization for (value > 2) is not yet visible. But why is there no mistake for o2 that sees 2 matching specializations !?
I assume that the compiler should select Unique<3>::type with some arbitrary name when it is first encountered, and then replace Unique<3>::type everywhere with that name.

Is this a compilation error or a C ++ or C ++ โ€œfunctionโ€ error?

+6
source share
3 answers

B 14.5.5.1. The mapping of partial specializations of the template template is

If more than one relevant specialization is found, the partial order rules (14.5.5.2) are used to determine if one of the specializations is more specialized than the others. If none of the specializations is more specialized than all other relevant specializations, then using the class template is ambiguous and the program is poorly formed.

However, this only applies to your first case, when two specializations are visible, and I am not yet sure that these two specializations are valid on their own.

In your second case, however, before reaching the second specialization, the id id Unique<3> template already exists for which (thanks to nm, Matthieu M., James Kanze) the first specialization has already been created:

14.5.5 Partial specialization of the template template

Partial specialization must be declared before the first use of a class template specialization, which would use partial specialization as a result of implicit or explicit instantiation in each translation unit in which such use occurs; no diagnostics required.

And at 14.5.5, paragraph 8

The following restrictions apply to the partial template specialization argument list:

- a partially specialized expression of a non-type of an argument should not contain a parameter of the template partial specialization, unless 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 are not involved in creating the specialization unless they are used as a simple identifier (thus Range<(value > 2)> will be wrong).

So, it seems that your code is poorly formed.


Not directly related, but still interesting in this regard:

14.7.3 Explicit Specialization

Placing explicit specialization declarations for function templates, class templates, member functions of class templates, static data elements for class templates, member classes of class templates, member class templates for class templates, member function templates for class templates, member functions for member class template templates, member functions of member templates of classes without templates, member functional templates of member classes of class templates, etc., as well as the placement of a partial specialization of declaring class templates, member class templates in classes without templates, class templates member class templates, etc. may affect the correct formation of the program in accordance with the relative positioning of explicit declarations of specialization and their points of instantiation in the translation unit, as described above and below. When writing a specialization, be careful with its location; or there will be such a test to compile it to ignite its self-immolation.

+2
source

A template is created the first time it is used (per translation unit), and not every time.

+3
source

o1 does not see the second specialization because of this:

14.5.5 / 1 Partial specialization must be declared before the first use of the class, which would use partial specialization as a result of implicit or explicit instantiation in each translation unit in which such use occurs; no diagnostics required.

In the second example, the second specialization will be used when creating Unique<3> if it were seen before the declaration o1 . Since this rule is violated, the program is interrupted, and the compiler is allowed to remain silent about it.

o2 does not see the second specialization, because it does not see any specialization at all. Its class is created once, at the point of declaration o1 .

+2
source

Source: https://habr.com/ru/post/910065/


All Articles