Can a class template explicit specialization also declare something else? - c++

It would be nice if this code were invalid. But it's conceptually sound, and GCC accepts it although Comeau doesn't:
template< typename > struct t;
template<> struct t< int > {} r; // Bad declarator! Don't pee on the carpet!
(Edit: the above compiles but r seems no to be declared into any scope, so it is essentially ignored.)
Explicit specializations populate a kind of nether region between templates and classes. The type declared by an explicit specialization is complete once it is defined. From the compiler's standpoint, it is not a template. If it were a parameterized template, declaring an object would be impossible. Consider §14/3:
In a template-declaration, explicit specialization, or explicit instantiation the init-declarator-list in the dec- laration shall contain at most one declarator. When such a declaration is used to declare a class template, no declarator is permitted.
What does "is used to declare a class template" mean? Clearly a primary template declares a class template. And a partial specialization does too, according to §14.5.5/1 (FDIS numbers):
A template declaration in which the class template name is a simple-template-id is a partial specialization of the class template named in the simple-template-id.
When it comes to explicit specializations, though, the Standard speaks in terms of a declaration preceded by the token sequence template<>. It looks like a template and it names a template-name, but it doesn't seem to declare a template.
The really bizarre thing is that §14/3 restricts the number of declarators to "at most one." A function template declaration, explicit specialization or instantiation must have exactly one declarator. Any declaration involving a class template must have exactly zero… except explicit specialization, which seems to fall through the cracks. Faithfully, GCC refuses to allow
template<> struct t< int > {} r, s; // Offer valid one per specialization.
I tend to agree with GCC's interpretation, nonsense as it may be. Unfortunately, it may be inhibiting its ability to detect missing semicolons. Please, let the number of allowed declarators be exactly zero!

Several points: first, explicit specializations are not in a nether
region between templates and classes; an explicit specialization is a
class, period. The only relation is has with templates (except for the
funny name) is that it will be used instead of a template instantiation
if the template is to be instantiated on the specialization type.
Secondly, if there is a problem with the paragraph in §14/3 that you
cite, it is that it includes explicit instantiation; an explicit
instantiation is a class definition, and if
struct S {} s, *p;
is legal,
template<> struct T<int> {} s, *p;
should be too. (I would argue against allowing either, but that train
has already left the station, and since C allows the first, we're stuck
with it.)
Otherwise, the statement in §14/3 is a bit irrelevant. A function
template must have exactly one declarator, and a class template exactly
zero; there's no need to try to englobe them both in some "at most one"
gobbledygook. (If I were designing the language from scratch, I'd not
allow any declarator in a declaration which defined a class or enum
type. But again, it's too late for that.)
And I agree that it's a bother:
template<> struct T<int> {}; // Requires a ';'
template<> void f<int>() {} // ';' forbidden
(At least C++11 will allow a semicolon after the function definition.)

Explicit specialization and explicit instantiation do not declare a template. They declare a template-id which refers to a specialization, which is a class.
However, this doesn't validate my example. The problem is that everything declared following template or template<> is part of the explicit instantiation or specialization, respectively. Only certain types of entities may be specialized or instantiated, and previously-undeclared names aren't one of them.
Consider these examples making gratuitous, but legal use of elaborated-type-specifiers (§7.1.5.3):
template< typename T > struct s;
template< typename T > s< int > *f() {}
template<> struct u *f< char >(); // struct u is declared
u *p = 0; // see, we can use its name now.
template<> struct s< int > *f< int >(); // s<int> declared but not specialized
template struct s< int > *f< long >(); // s<int> declared but not instantiated
As far as I can tell, the Standard is fuzzy about specifying which declared name is the one specialized. The language does weakly imply that each such declaration applies to only one template: §14.7.2/2
If the explicit instantiation is for a class, a function or a member template specialization…
and §14.7.3/2
An explicit specialization shall be declared in the namespace of which the template is a member…
The only way to resolve this is to ignore the type declaration if the declarator also specifies a legal instantiation/specialization.
Getting to the point, the examples in the question specify illegal specializations in the declarator and then expect the compiler to backtrack and specialize the type instead. Given the explicit lists of what specializations and declarations are allowed to do in §14.7.2/1 and §14.7.3/1, it seems more reasonable to complain about template<> struct t< int > {} r; that r is not a function template, member function template, static data member of a class template, etc.

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

When instantiating a template, should members of its incomplete argument types be visible?

In the following example, A has a member typedef Instantiate which causes the instantiation of B<A>.
template<typename T>
struct B
{
typedef typename T::Before Before; // ok
typedef typename T::After After; // error: no type named 'After' in 'A<int>'
};
template<typename T>
struct A
{
typedef int Before;
typedef typename B<A>::After Instantiate;
typedef int After;
};
template struct A<int>; // instantiate A<int>
All the compilers I've tried report that, while A::Before is visible, A::After is not. Is this behaviour compliant with the standard? If so, where does the standard specify which names in A should be visible during instantiation of B<A>?
If dependent names are "looked up at the point of the template instantiation", what does this mean in the scenario of a name qualified by a template parameter such as T::After?
EDIT: Note that the same behaviour occurs when A is not a template:
template<typename T>
struct B
{
typedef typename T::Before Before; // ok
typedef typename T::After After; // error: no type named 'After' in 'A'
};
struct A
{
typedef int Before;
typedef B<A>::After Instantiate;
typedef int After;
};
.. and G++ accepts the following, but Clang does not:
template<typename T>
struct B
{
static const int value = 0;
static const int i = T::value; // clang error: not a constant expression
};
struct A
{
static const int value = B<A>::value;
};
EDIT: After some reading of the C++03 standard:
[temp.dep.type] A type is dependent if it is a template parameter
Therefore T is dependent.
[temp.res] When looking for the declaration of a name used in a template definition, the usual lookup rules are used for nondependent names. The lookup of names dependent on the template parameters is postponed until the actual template argument is known.
The lookup of T::After is therefore postponed until the argument for T is known.
[temp.inst] Unless a class template specialization has been explicitly instantiated ... the class template specialization is implicitly instantiated when the specialization is referenced in a context that requires a completely-defined object type.
Therefore the declaration of A<int>::Instantiate requires the instantiation of B<A> (because it is used in a nested-name-specifier.)
A<int>::After is not visible at the point of declaration of A<int>::Instantiate, so the behaviour of the compiler makes sense - but I haven't seen anything in C++03 that explicitly describes this behaviour. The closest thing was this somewhat vague paragraph:
[temp.dep.res]
In resolving dependent names, names from the following sources are considered:
— Declarations that are visible at the point of definition of the template.
Whether typename T::Before is valid is not explicitly said by the spec. It is subject of a defect report (because the Standard can very reasonably be read to forbid it): http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#287 .
Whether typename T::After is invalid can also very reasonably be read to be true by the spec, and actually it makes quite a bit of sense (and aforementioned DR still keeps it ill-formed). Because you have an instantiation of a class A<Foo>, which references another class A<Bar> during a period where a member Baz has not yet been declared, and that makes a reference back to A<Foo>::Bar. That is ill-formed in the case of non-templates aswell (try to "forget" for a moment that you are dealing with templates: surely the lookup of B<A>::After is done after the A template was completely parsed, but not after the specific instantiation of it was completely created. And it is the instantiation of it that actually will do the reference!).
struct A {
typedef int Foo;
typedef A::Foo Bar; // valid
typedef A::Baz Lulz; // *not* valid
typedef int Baz;
};
T::Before and T::After are dependent names due to [temp.dep.type]/8 and /5.
Dependent names are looked up "at the point of the template instantiation (14.6.4.1) in both the context of the template definition and the context of the point of instantiation." [temp.dep]/1
I interpret this as: They're looked up when the template is instantiated. Where are they looked up? At the context of the template definition and the context of the point of instantiation.
[temp.dep.type]/7 On the other hand states:
If, for a given set of template arguments, a specialization of a template is instantiated that refers to a member of the current instantiation with a qualified-id or class member access expression, the name in the qualified-id or class member access expression is looked up in the template instantiation context.
[temp.point]/7 Defines the instantiation context as follows:
The instantiation context of an expression that depends on the template arguments is the set of declarations with external linkage declared prior to the point of instantiation of the template specialization in the same translation unit.
Therefore, we need to know what the point of instantiation is.
[temp.point]/4
For a class template specialization [...], 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.
Although the injected class name A is arguably a context that depends (as a layman term) on the template parameters of A, the name A itself is not a dependent name. Correction by Johannes Schaub: It is a dependent name. See [temp.local]/1 and [temp.dep.type]/8 => A is a dependent type.
Therefore, this condition is not fulfilled, and B<A> should be instantiated before A<int>.

How do I give template arguments to an object created inline with its class?

I know that in C++ we can do this:
class A {} a;
This makes an object of type A named a. It's equivalent to:
A a;
I was wondering how I would do this with templates. For example:
template <typename T> struct N {} <int> n;
This doesn't compile, but you get the idea. How would I specify the template arguments to an object created inline with its class definition? Is this even possible?
The stuff after the closing } is called an init-declarator-list according to the standard.
14.3 explicitly forbids them to be used in template class declarations:
In a template-declaration, explicit specialization, or explicit
instantiation the init-declarator-list in the dec- laration shall
contain at most one declarator. When such a declaration is used to
declare a class template, no declarator is permitted.
I don't think you can do that. The form you mentioned, for structures and classes is kept, from my understanding, for backward compatibility with c - where you could do that for structs.
Nice idea, though :)
You can't declare variables from a template definition, not even if all template arguments have defaults.
This also is an error:
template <typename T = int> struct N {} n;
http://ideone.com/vFlIEg

Class member visibility in member function declaration signature

Why does this work:
template <typename A>
struct S {
A a;
template <typename B>
auto f(B b) ->
decltype(a.f(b))
{
}
};
But this does not (a and f swapped places):
template <typename A>
struct S {
template <typename B>
auto f(B b) ->
decltype(a.f(b))
{
}
A a;
};
saying that a is not declared in that scope (inside decltype) but adding explicit this-> makes it work.
template <typename A>
struct S {
A a;
template <typename B>
auto f(B b) ->
decltype(a.f(b))
{
}
};
This works because within a trailing return type, members of the surrounding class are visible. Not all members, but only the members that are declared prior to it (in a trailing return type, the class is not considered to be complete, as opposed to function bodies). So what is done here:
As we are in a template, a lookup is done to see whether a is dependent or not. Since a was declared prior to f, a is found to refer to a class member.
By the template rules in C++, it is found that a refers to a member of the current instantiation since it is a member of instantiations of the surrounding template. In C++, this notion is used mainly to decide whether names are dependent: If a name is known to refer to the surrounding template's members, it is not necessarily needed to be looked up when instantiating, because the compiler already knows the code of the template (which is used as the basis of the class type instantiated from it!). Consider:
template<typename T>
struct A {
typedef int type;
void f() {
type x;
A<T>::type y;
}
};
In C++03, the second line declaring y would be an error, because A<T>::type was a dependent name and needed a typename in front of it. Only the first line was accepted. In C++11, this inconsistency was fixed and both type names are non-dependent and won't need a typename. If you change the typedef to typedef T type; then both declarations, x and y will use a dependent type, but neither will need a typename, because you still name a member of the current instantiation and the compiler knows that you name a type.
So a is a member of the current instantiation. But it is dependent, because the type used to declare it (A) is dependent. However this doesn't matter in your code. Whether dependent or not, a is found and the code valid.
template <typename A>
struct S {
template <typename B>
auto f(B b) ->
decltype(a.f(b))
{
}
A a;
};
In this code, again a is looked up to see whether it is dependent and/or whether it is a member of the current instantiation. But since we learned above that members declared after the trailing return type are not visible, we fail to find a declaration for a. In C++, besides the notion "member of the current instantiation", there is another notion:
member of an unknown specialization. This notion is used to refer to the case where a name might instead refer to a member of a class that depends on template parameters. If we had accessed B::a, then the a would be a member of an unknown specialization because it is unknown what declarations will be visible when B is substituted at instantiation.
neither a member of the current, nor a member of an unknown specialization. This is the case for all other names. Your case fits here, because it is known that a can never be a member of any instantiation when instantiation happens (remember that name lookup cannot find a, since it is declared after f).
Since a is not made dependent by any rule, the lookup that did not find any declaration is binding, meaning there is no other lookup at instantiation that could find a declaration. Non-dependent names are lookup up at template definition time. Now GCC rightfully gives you an error (but note that as always, an ill-formed template is not required to be diagnosed immediately).
template <typename A>
struct S {
template <typename B>
auto f(B b) ->
decltype(this->a.f(b))
{
}
A a;
};
In this case, you added this and GCC accepted. The name a that follows this-> again is lookup at to see whether it might be a member of the current instantiation. But again because of the member visibility in trailing return types, no declaration is found. Hence the name is deemed not to be a member of the current instantiation. Since there is no way that at instantiation, S could have additional members that a could match (there are no base classes of S that depend on template parameters), the name is also not a member of an unknown specialization.
Again C++ has no rules to make this->a dependent. However it uses this->, so the name must refer to some member of S when it is instantiated! So the C++ Standard says
Similarly, if the id-expression in a class member access expression for which the type of the object expression is the current instantiation does not refer to a member of the current instantiation or a member of an unknown specialization, the program is ill-formed even if the template containing the member access expression is not instantiated; no diagnostic required.
Again no diagnostic is required for this code (and GCC actually doesn't give it). The id-expression a in the member access expression this->a was dependent in C++03 because the rules in that Standard were not as elaborated and fine-tuned as in C++11. For a moment let's imagine C++03 had decltype and trailing return types. What would this mean?
The lookup would have been delayed until instantiation, because this->a would be dependent
The lookup at instantiation of, say, S<SomeClass> would fail, because this->a would not be found at instantiation time (as we said, trailing return types do not see members declared later).
Hence, the early rejection of that code by C++11 is good and useful.
The body of a member function is compiled as if it was defined after the class. Therefore everything declared in the class is in scope at that point.
However, the declaration of the function is still inside the class declaration and can only see names that precede it.
template <typename A>
struct S {
template <typename B>
auto f(B b) ->
decltype(a.f(b)); // error - a is not visible here
A a;
};
template <typename A>
template <typename B>
auto S<A>::f(B b) ->
decltype(a.f(b))
{
return a.f(b); // a is visible here
}
The Standard says (section 14.6.2.1):
If, for a given set of template arguments, a specialization of a template is instantiated that refers to a member of the current instantiation with a qualified-id or class member access expression, the name in the qualified-id or class member access expression is looked up in the template instantiation context.
this->a is a class-member access expression, therefore this rule applies and lookup takes place at the point of instantiation, where S<A> is complete.
Finally, this doesn't solve your problem at all, because section 5.1.1 says:
If a declaration declares a member function or member function template of a class X, the expression this is a prvalue of type “pointer to cv-qualifier-seq X” between the optional cv-qualifier-seq and the end of the function-definition, member-declarator, or declarator. It shall not appear before the optional cv-qualifier-seq
and it shall not appear within the declaration of a static member function (although its type and value category are defined within a static member function as they are within a non-static member function).
So you can't use this-> here, since it is before the cv-qualifier-seq part of the function declaration.
Wait, no it isn't! Section 8.4.1 says
The declarator in a function-definition shall have the form
D1 ( parameter-declaration-clause) cv-qualifier-seq opt ref-qualifier opt exception-specification opt attribute-specifier-seq opt trailing-return-type opt

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.