§14.7.3 [temp.expl.spec]/p7:
The placement of explicit specialization declarations for function
templates, class templates, variable templates, member functions of
class templates, static data members of class templates, member
classes of class templates, member enumerations of class templates,
member class templates of class templates, member function templates
of class templates, static data member templates of class templates,
member functions of member templates of class templates, member
functions of member templates of non-template classes, static data
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, variable templates,
member class templates of non-template classes, static data member
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.
In particular (§14.7.3 [temp.expl.spec]/p6),
If a template [...] is explicitly specialized then that specialization
shall be declared before the first use of that specialization that
would cause an implicit instantiation to take place, in every
translation unit in which such a use occurs; no diagnostic is
required. If the program does not provide a definition for an
explicit specialization and [...] the specialization is used in a way
that would cause an implicit instantiation to take place [...],
the program is ill-formed, no diagnostic required.
The explicit specialization base_traits<derived>
must be declared and defined before the definition of derived
, as otherwise both inheriting from base<derived>
and using base_traits<derived>::value_t
would trigger an implicit instantiation. Thus:
template <class D>
struct base_traits;
template <class D>
struct base
{
typedef typename base_traits<D>::value_t value_t;
};
struct derived;
template<>
struct base_traits<derived>
{
typedef int value_t;
};
struct derived : base<derived>
{
typedef base_traits<derived>::value_t value_t;
};