2
votes

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
The forward declaration of S<char> made it impossible for you to incorrectly compile a program that instantiates the general template for object - isn't that a practical application?Casey
Partial specialization declarations themselves are not found by name lookup. Rather, when the primary template name is used, any previously declared partial specializations of the primary template are also considered.n. 1.8e9-where's-my-share m.
I don't really understand the question... why would you want to forward-declare a specialisation? Just don't do it...Kerrek SB
@KerrekSB To prevent the primary template from being instantiated when it shouldn't be?jthill
@jthill: I don't think that's possible. At the point where you're instantiating a template, all specializations must already be known.Kerrek SB

1 Answers

4
votes

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>;
}