问题
The C++98 standard says:
[temp.class.spec] Partial specialization declarations themselves are not found by name lookup.
If this is also true for explicit specializations, this makes a forward-declaration of a class template explicit/partial specialization invisible.
[temp.class.spec.match] 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.
This implies that the choice of explicit/partial specialization is not made until the point of (implicit) instantiation of a matching specialization - which only occurs when the class is required to be completely defined.
In the following example, the only effect the forward-declared explicit-specializations have is to make the program fail to compile.
namespace N
{
template<class T>
struct S
{
};
typedef S<char> Type; // name lookup finds S<T>
template<>
struct S<char>; // invisible to name lookup
typedef S<char> Type; // name lookup finds S<T>
int f(S<char>*); // name lookup finds S<T>
S<int> object; // implicitly instantiates S<int>
template<>
struct S<int>; // illegal, explicit specialization after instantiation
}
N::S<char>* p = 0; // name lookup finds N::S<T>
int i = f(p); // name lookup finds N::f via ADL
N::S<char> object; // illegal, incomplete type N::S<char>
In both cases, the only way to make the program compile (apart from deleting the specializations) is to provide a definition for both specializations before they are instantiated - which makes the forward-declaration a bit pointless.
Does this behaviour have any practical real-world application? Apart from this, is there anything these forward-declarations are useful for?
回答1:
It is not true that the only purpose is to make the program fail to compile. In the following, V2
is "ill-formed; no diagnostic required", while V1 is well-formed.
namespace N {
template<typename T> struct A {
friend void f(A *a) { } // would take this with V2
};
}
void f(void*) { } // would take this with V1
namespace N {
/* V1: */ template<> struct A<int>;
}
int main() {
N::A<int> *p;
f(p);
}
namespace N {
/* V2: */ template<> struct A<int>;
}
来源:https://stackoverflow.com/questions/17200312/whats-the-point-of-forward-declaring-a-class-template-explicit-partial-speciali