Clarification on partial template specialisation - c++

This question seeks clarification on a section of the following documentation on partial template specialisation:
partial template specialization
My question pertains to the following text under the heading Members of partial initialization:
If a class template is a member of another class template, and it has
partial specializations, these specializations are members of the
enclosing class template. If the enclosing template is instantiated,
the declarations of each member partial specialization is instantiated
as well (the same way declarations, but not definitions, of all other
members of a template are instantiated)
If the primary member template is explicitly (fully) specialized for a
given (implicit) specialization of the enclosing class template, the
partial specializations of the member template are ignored for this
specialization of the enclosing class template.
If a partial specialization of the member template is explicitly
specialized for a given (implicit) specialization of the enclosing
class template, the primary member template and its other partial
specializations are still considered for this specialization of the
enclosing class template.
The example section demonstrating above mentions the following:
template<class T> struct A { // enclosing class template
template<class T2>
struct B {}; // primary member template
template<class T2>
struct B<T2*> {}; // partial specialization of member template
};
template<>
template<class T2>
struct A<short>::B {}; // full specialization of primary member template
// (will ignore the partial)
A<char>::B<int*> abcip; // uses partial specialization T2=int
A<short>::B<int*> absip; // uses full specialization of the primary (ignores partial)
A<char>::B<int> abci; // uses primary
I don't understand the distinction between the three cases above, which warrant a different treatment in each case, based on the text reproduced above.
Can anyone provide a simple explanation?

Since I am not sure that i got your question correctly, so please be indulgent. I assume that you want to know the difference and the reason for the behavior in your presented instantiations.
First you need to know how the compiler chooses which template specialization to use. There is a nice explanation here, but it mostly breaks down to: The compiler chooses always the template most restricted/specialized template specialization.
So now, lets look at the first instantiation you do there:
A<char>::B<int*> abcip;
Since there exists no full specialization for A<char>::B, we look into the general definition of A and find two matching template specializations for B<int*>.
B<T2> with T2=int* and B<T2*> with T2=int.
Since B<T2*> is the more restricted one, we choose this one.
Lets now look at the second instantiation:
A<short>::B<int*> absip;
Paragraph 2 of your quoted text now applies, since there exists a full specialisation of the primary member template A<short>::B. The partial specialization A<T>::B<T2*> will not be considered. This makes sense due to the fact that A<short>::B<T2> is more specialized than A<T>::B<T2*>. Things would change if we were to add the following to your code:
template<>
template<class T2>
struct A<short>::B<T2*> {};
Since this is even more specialized, it would be the chosen template for this instantiation.
The last instantiation simply chooses the primary member template A<T>::B<T2>, because this is the only matching type.

Related

The implicit instantiation for a member class template when the specialization is referenced in the enclosing class template

#include <iostream>
template<typename T>
struct A{
template<typename U>
struct B{};
B<T> b; //#2
};
//#3
int main() {
A<int> a; // #1
}
Consider the above code, the use of the template-id A<int> causes an implicit instantiation for specialization A<int>. According to the following rule:
temp.point#4
For a class template specialization, a class member template specialization, or a specialization for a class member of a class template, if the specialization is implicitly instantiated because it is referenced from within another template specialization, if the context from which the specialization is referenced depends on a template parameter, and if the specialization is not instantiated previous to the instantiation of the enclosing template, the point of instantiation is immediately before the point of instantiation of the enclosing template. Otherwise, the point of instantiation for such a specialization immediately precedes the namespace scope declaration or definition that refers to the specialization.
For the specialization referenced at #1, the Otherwise part of that rule will apply to it. That means, the point of instantiation for A<int> should at #3, there's no issue here. However, the instantiation for A<int> will cause the instantiation for specialization B<int> which is a member thereof. Hence, the if part of that rule will apply to B<int>. What I'm confused about is here. According to the relevant rule, the point of instantiation for B<int> shall be immediately before the point of instantiation of the enclosing template, that is, somewhere before #3, I can't understand here. If, think it through the normal class, there're only two ways to define its class member, one is to define the class member in the class definition, the other is to declare the class member in the class definition and then define the class member outside the class definition at some point where follows the classes definition.
Change the example by using a normal class:
struct Normal_A_Int{
struct Normal_B_Int{};
Normal_B_Int b;
};
int main(){
Normal_A_Int a;
}
That means, the definition for member class Normal_B_Int must be in the definition of the enclosing class due to the declaration Normal_B_Int b is required a complete class type.
So, how is it possible to let the definition for member class B<int> be placed at some point precede the definition for an enclosing class A<int>? At best, the definition for B<int> shall be in the definition for A<int>. How to interpret the POI for the first example?
The quote you provided from temp.point/4 is exactly the case:
template<typename T>
struct A {
template<typename U>
struct B { };
B<T> b;
};
// point-of-instantiation for A<int>::B<int>
// point-of-instantiation for A<int>
int main() {
A<int> a;
}
There's not much lawyering to do. The standard says those are the points of instantiation. Class templates are not classes and intuition doesn't necessarily carry over. They have both a definition and instantiation.
Take the outer class definition. If it is a class, the member's type must be defined. If it is a class template, the member's type must only be declared. You can lower the definition of B:
template<typename T>
struct A {
template<typename U> struct B;
B<T> b;
};
template<typename T>
template<typename U>
struct A<T>::B { };
You could not do this with classes (have an "incomplete" member in the definition), but you can with class templates.
So the question is, why is the point-of-instantiation of template A<T>::B<T> before that of A<T>? Ultimately, because the standard says so. But consider that if it were after, you couldn't have an inner class template at all. And if it were, say, inside the definition of A<T>, name lookup would misbehave because the names between the definition of A and the point of instantiation of A<int> would not be visible in A<int>::B<int>. So it actually makes some sense.
Perhaps the intuition comes from conflating definition and point-of-instantiation:
So, how is it possible to let the definition for member class B be placed at some point precede the definition for an enclosing class A?
It isn't. The point-of-instantiation controls name visibility. All names up to that point in the TU are visible. (It is not the definition.) From this point of view, it is clear intuitively that A<int>::B<int> should have a point-of-instantiation near to the point-of-instantiation of A<int> (they should see the same other names). If there is an ordering, probably the inner should come first (so that A<int> can have a A<int>::B<int> member). If there is not an ordering, there has to be language about how the instantiations are interleaved or interact.
There are two interesting aspects of this rule.
One is that templates can be specialized. So, to accomplish this requirement, when the compiler goes to instantiate A<int>, it must first select the specialization, process it enough to know it has a member class template and that it needs to instantiate it, and then stop everything to go instantiate A<int>::B<int> first. That is not difficult, but it is subtle. There is an instantiation stack, as it were.
The second aspect is far more interesting. You may expect from ordinary class intuition that the definition of B<T> can use things (e.g. typedefs) from A<T> that would in a template context require an instantiation of A<T> which doesn't yet exist when A<T>::B<T> is being instantiated. Like:
template<typename T>
struct A {
using type = T;
template<typename U>
struct B { using type = typename A<U>::type; };
B<T> b;
};
Is that OK?
If the point-of-instantiation of A<int>::B<int> is before that of A<int>, we cannot really form A<int>::type.
This is the realm of CWG287 and P1787.
CWG287 proposed that the point-of-instantiations be the same (one is not before the other). Further, it would add:
If an implicitly instantiated class template specialization, class member specialization, or specialization of a class template references a class, class template specialization, class member specialization, or specialization of a class template containing a specialization reference that directly or indirectly caused the instantiation, the requirements of completeness and ordering of the class reference are applied in the context of the specialization reference.
In my example, A<int>::B<int> references A<int> which directly caused its instantiation by way of reference to B<int>, so the requirements of completeness and ordering of the class reference (typename A<int>::type) are applied in the context of the specialization reference (B<int> b). So it is OK. It is still OK if the typedef is below the definition of B. But if we move the typedef below the member b, it will be ill-formed! Subtle! This has the effect of interleaving the instantiations. When we see the member, we stop what we're doing, go off to instantiate A<int>::B<int>, but we can use the ordering and completeness requirements from where we were in the instantiation of A<int>. The point-of-instantiation is the same, so we can also use the same declarations from the TU.
CWG287 seems to aim at replicating what compilers do already. However, CWG287 has been open since 2001. (See also this and this.)
P1787 which seems to be targeted at C++23, aims to rewrite a lot of subtle language. I think aims to have similar effect as CWG287. But to do so, they had to so thoroughly re-define name lookup that it is very difficult to me to know that. :)
Well I did run CppInsights on your first example:
https://cppinsights.io/lnk?code=dGVtcGxhdGU8dHlwZW5hbWUgVD4Kc3RydWN0IEF7CiAgICB0ZW1wbGF0ZTx0eXBlbmFtZSBVPgogICAgc3RydWN0IEJ7fTsKICAgIEI8VD4gYjsKfTsKCmludCBtYWluKCkgewogICAgQTxpbnQ+IGE7Cn0KCgoK&insightsOptions=cpp2a&std=cpp2a&rev=1.0

The issue about name that refer to current instantiation for partial specialization

temp.dep.type#1.4
A name refers to the current instantiation if it is
in the definition of a partial specialization or a member of a partial specialization, the name of the class template followed by the template argument list of the partial specialization enclosed in <> (or an equivalent template alias specialization). If the nth template parameter is a parameter pack, the nth template argument is a pack expansion whose pattern is the name of the parameter pack.
Please note the emphasized part of the above bullet, Firstly, the template parameter here is not clear, Is it refer to the template parameter of the primary template or the partial specialization?
Example 1
If the template parameter refer to one of the primary template, then consider the following example:
#include <iostream>
template<typename...T>
struct Test{};
template<typename T>
struct Test<T>{
Test<T>* ptr; // here is not a pack expansion
};
Is the Test<T> not a name that refer to current instantiation?
Example 2
If the template parameter refer to one of the partial specialization, then consider the following example:
template<typename T>
struct Test{};
template<typename...Args>
struct Test<void(*)(Args*...)>{
Test<void(*)(Args*...)>* ptr; // the pattern is Args*, not the name of parameter pack
};
Whether the template parameter refer to that of the primary template or the partial specialization, the form of corresponding template-argument seems do not satisfy the emphasized part of the bullet. However, In my understanding, Test<T> in example 1 and Test<void(*)(Args*...)> in example 2 all should be names that refer to current instantiation.
So, my question is:
which the template parameter in the bullet refer to?
Are these names that refer to current instantiation in two examples?
Is the emphasized part of the bullet a redundant sentence?

What exactly happens in this template metaprogramming snippet?

template <typename T, typename = void>
struct IsIterable : std::false_type {};
template <typename T>
struct IsIterable<
T,
decltype(
std::begin(std::declval<std::add_lvalue_reference_t<T>>()),
std::end(std::declval<std::add_lvalue_reference_t<T>>()),
void()
)
> : std::true_type {};
I thought I understood this.
The first IsIterable is a class template with a default template argument for the second parameter. It obviously is applicable for every type.
The second part is a partial template specialization of IsIterable. Thanks to SFINAE, it is only chosen when T has the member functions begin() and end().
Here is my first question I just came up with actually: the base template has a default argument, so this means it still has two template parameters. The partial specialization only has one template parameter. So does this mean that "one template parameter" always gets choosen before "two template parameters, one default"?
Also, do I understand it correctly that the first "base" template inherits from false_type, and the partial template specialization "adds" another inheritance level? (so does the partial specializations inheritance hierarchy look like this: false_type > true_type > IsIterable, where the definitions of false_type are hidden by true_type?)
Now onto my actual question. Why does the decltype expression have to evaluate to void? I thought that it wouldn't matter and I could write
template <typename T>
struct IsIterable<
T,
decltype(
std::begin(std::declval<std::add_lvalue_reference_t<T>>()),
std::end(std::declval<std::add_lvalue_reference_t<T>>()),
bool() // **** change here ****
)
> : std::true_type {};
as well. But this makes it so that the value of IsIterable is always false! Why is, when I change the partial specialization from void to bool, always the first template chosen?
So does this mean that "one template parameter" always gets choosen before "two template parameters, one default"?
No. A partial specialization is used when an instantiation matches its template argument list, and when it is "more specialized" than any other partial specializations that match (which is not relevant here, because there are no other partial specializations declared).
When you instantiate the template as IsIterable<Foo> the default template argument is used, so the instantiation is IsIterable<Foo, void>. If Foo has begin() and end() members then IsIterable<Foo, void> matches the partial specialization, which is more specialized than the primary template. When Foo doesn't have begin() and end() members the partial specialization is not usable, because the expression decltype(std::declval<T>().begin(), std::declval<T>().end(), void()) causes a subsitution failure when Foo is substituted in place of T.
Also, do I understand it correctly that the first "base" template inherits from false_type, and the partial template specialization "adds" another inheritance level?
No. There is no implicit inheritance relationship between a primary template and a specialization. (If you stop calling it a "base" template and call it by its proper name, the primary template, maybe you won't think there is any kind of "base" class relationship.)
When a partial specialization (or an explicit specialization) is used it is used instead of the primary template, not in addition to it.
Why does the decltype expression have to evaluate to void?
Because that's the type of the default template argument on the primary template. You are not supposed to provide an argument for the second template parameter, it's supposed to use the default, and that is void.
Why is, when I change the partial specialization from void to bool, always the first template chosen?
Because when you write IsIterable<Foo> that uses the default template argument, so is equivalent to IsIterable<Foo, void> which can never match a partial specialization of the form IsIterable<T, bool> because void is not the same type as bool!
If you made the partial specialization use bool() instead then you would have to write IsIterable<Foo, bool> for the partial specialization to match. You could do that ... but it's not how the trait is designed to be used. Alternatively you could change the default template argument on the primary template to be bool as well, but void is the idiomatic choice, since the specific type doesn't matter, all that matters is the default matches the specialization. You're meant to provide only one template argument and let the default be used for the second. And the partial specialization can only match if its second template argument is the same as the default template argument.
The second part is a partial template specialization of IsIterable. Thanks to SFINAE, it is only chosen when T has the member functions begin() and end().
That's not all there is. The expression t.begin(), t.end(), void() for a t of type T must also have a valid type and that must be void for the specialization to be selected. (That's what the decltype achieves.)
Here is my first question I just came up with actually: the base template has a default argument, so this means it still has two template parameters. The partial specialization only has one template parameter. So does this mean that “one template parameter” always gets choosen before “two template parameters, one default”?
Every valid instantiation of the specialization is also a valid instantiation of the base case (it's an implication) so the specialization (if viable) is a better match.
Also, do I understand it correctly that the first “base” template inherits from false_type, and the partial template specialization “adds” another inheritance level? (so does the partial specializations inheritance hierarchy look like this: false_type > true_type > IsIterable, where the definitions of false_type are hidden by true_type?)
No, they are completely unrelated types. A specialization of a class template does not inherit implicitly from the general case.
If you want to see this live, try adding a large non-static data member (eg int[100]) to the general case and then compare the sizeof the instantiated types. If the special case is smaller, it cannot possibly be derived from the general case.
Now onto my actual question. Why does the decltype expression have to evaluate to void?
It doesn't have to but in order to make this work, you'll also have to change the default for the base case from void to bool or whatever. Be aware, however, that an overloaded operator, could cause you strange surprises if you pick anything but void.
The technique was nicely explained in a talk Walter Brown gave at CppCon 2014. If you have two hours sparse, I strongly recommend you watch the recording of his talk:
Walter E. Brown, Modern Template Metaprogramming: A Compendium, Part I. CppCon 2014.
Walter E. Brown, Modern Template Metaprogramming: A Compendium, Part II. CppCon 2014

Can a single member of a class template be partially specialized?

I came across an interesting point that I wasn't able to explain or find an explanation for. Consider the following template definition (compiled with mingw g++ 4.6.2):
template <typename T, typename S>
class Foo
{
public:
void f(){}
void g(){}
};
Should we want to, we can fully specialize any single member function:
template <>
void Foo<char,int>::f() {}
But partial specialization fails with an "invalid use of incomplete type 'class Foo<...>'" error:
template <typename T, typename S>
void Foo<T,S*>::f()
{
}
template <typename T>
void Foo<T,int>::f()
{
}
And I can't figure out why. Is it a conscious design decision made to avoid some problem I can't foresee? Is it an oversight?
The notion of partial specialization only exists for class templates (described by §14.5.5) and member templates (i.e. members of a template class that are themselves template functions, described by §14.5.5.3/2). It does not exist for ordinary members of class templates, nor does it exist for function templates – simply because it is not described by the Standard.
Now, you might argue that by giving the definition of a partial specialization of a member function, such as
template <typename T>
void Foo<T,int>::f()
{ }
you implicitly define a partial specialization of the class template: Foo<T,int>. That, however, is explicitly ruled out by the Standard:
(§14.5.5/2) Each class template partial specialization is a distinct template and definitions shall be provided for the members of a template partial specialization (14.5.5.3).
(§14.5.5.3/1) [...] The members of the class template partial specialization are unrelated to the members of the primary template. Class template partial specialization members that are used in a way that requires a definition shall be defined; the definitions of members of the primary template are never used as definitions for members of a class template partial specialization. [...]
The latter implies that it is impossible to implicitly define a partial specialization by simply giving the definition of one of its members: The very existence of that member would not follow from the definition of the primary template, hence defining it is equivalent to defining a member function that wasn't declared, and that isn't allowed (even with non-template classes).
On the other hand, the notion of explicit specialization (or full specialization, as you call it) exists for member functions of class templates. It is explicitly described by the Standard:
(§14.7.3/1) An explicit specialization of any of the following:
[...]
— member function of a class template
[...]
can be declared by a declaration introduced by template<>; [...]
§14.7.3/14 describes the details:
(§14.7.3/14) A member or a member template of a class template may be explicitly specialized for a given implicit instantiation of the class template, even if the member or member template is defined in the class template definition. [...]
Hence, for explicit specializations of members, the instantiation of the rest of the class template works implicitly – it is derived from the primary template definition, or any partial specializations if defined.
I tried to find a succinct quote from the standard, but I don't think there is one. The fact is, there is no such thing as a partial specialization of a template function (or, for that matter, of a template alias). Only class templates can have partial specializations.
Let's forget about templates for a second. In C++, there is a big difference between class names and function names. There can only be one definition of a class within a given scope. (You can have various declarations, but they all refer to the One True Class.) So the name really identifies the class.
A function name, on the other hand, is a kind of group identity. You can define any number of functions within a scope with exactly the same name. When you use a function name to call a function, the compiler has to figure out which function you really meant by looking at the various possibilities and matching the signature of each of them with the supplied arguments. There's no relationship between the various functions which share a name; they're completely separate entities.
So, no big deal. You knew all this, right? But now let's go back to templates.
The name of a templated class is still unique. Although you can define partial specializations, you have to explicitly specialize the same templated class. This mechanism looks superficially like the function-name resolution algorithm referred to above, but there are significant differences -- one of them is that, unlike function prototypes, you cannot have two class templates in the same scope with different kinds of template parameters.
Templated functions, on the other hand, have no need to define unique names. Templating does not replace the normal function overload mechanism. So when the compiler is trying to figure out what a function name means, it has to consider all templated and non-templated declarations for that function name, resolve the templated ones to a set of template parameter assignments (if possible) and then once it has a list of possible function objects, select the best one with normal overload resolution.
That's quite a different algorithm from the templated class template parameter resolution. Instead of just matching a list of provided template arguments with a list of declared template parameters, which is how it resolves class templates, it has to take each templated function which might possibly match (has at least the right number of parameters, for example); deduce template parameters by unifying the supplied arguments with the template; and then add the resolve specialization to the overload set for a further round of overload resolution.
I suppose it would have been possible to have added partial specialization resolution into that process as well, but the interactions between partial specialization and function overloading strike me as likely to lead to pseudo-magical behaviour. In the event, it wasn't necessary and so there is no such mechanism. (You can fully specialize a function template. Full specialization means that there are no template arguments to deduce, so it's not a problem.)
So that's the scoop: you can't partially specialize a templated function, but there is nothing stopping you from providing any number of function templates with the same name. All of them will be considered in overload resolution, and the best one will win, as usual.
Usually, that's actually sufficient for your overloading needs. You should think about templated functions just the same way you think about normal functions: come up with a way to select the one you want based on the supplied arguments. If you feel you really need to supply template parameters in a function call, rather than having them be deduced, just make the function a (possibly static) member of a templated class, and supply the template arguments to the class.
Hope that helps...
I think that the difference is that when you do the first (valid) explicit specialization of f:
template <>
void Foo<char,int>::f() {}
You are doing an implicit instantiation of Foo<char,int>. But when you try the partial specialization with:
template <typename T>
void Foo<T,int>::f()
{
}
The compiler would need to instantiate implicitly Foo<T,int> before doing the specialization, but it cannot do that because of the T. And it fails.
You can check that is the case with the following code:
template <typename T, typename S>
class Foo
{
public:
void f(){}
void g(){}
};
template <>
void Foo<char,int>::f() //line 11
{}
template <>
class Foo<char,int> //line 15
{};
With g++ it gives the errors:
test.cpp:15:7: error: specialization of ‘Foo<char, int>’ after instantiation
test.cpp:15:7: error: redefinition of ‘class Foo<char, int>’
test.cpp:2:7: error: previous definition of ‘class Foo<char, int>’
With clang++ is a bit clearer:
test.cpp:15:7: error: explicit specialization of 'Foo<char, int>' after instantiation
class Foo<char,int>
^~~~~~~~~~~~~
test.cpp:11:6: note: implicit instantiation first required here
void Foo<char,int>::f()
^

Why SFINAE gets messed up when changing the place of the class template specialization? Is this a C++ bug?

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" ?
A template is instantiated the first time it is needed (in the
translation unit), not each time.
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.
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.