What does `class template Example<int>;` statement mean with C++11?

Viewed 1020

I've been referred to "Explicit Template Instantiation" at cplusplus.com, which gives the following example:

template <typename T> class Example
{
public:
    Example( T test )
    {
        _data = test;
    }
    void setTest(T test)
    {
        _data = T;
    }
private:
    T _data;
};

class template Example<int>;
class template Example<float>;
class template Example<double>;

Apart from what looks like an omission error to me where a type is attempted to be assigned to a member variable -- _data = T instead of what I assume should be _data = test -- what I don't understand is what do the last 3 lines declare or instruct the compiler to do, exactly?

I know what templates are, have built programs with them, and know in general about their instantiation and specialization. I do probably have some holes in the understanding of the latter two, but I typically instruct an explicit template instantiation using e.g. template class Example<int>; form and not the one shown in the snippet.

I've tried to compile the snippet using g++ -std=c++11 -pedantic and it compiles just fine and without warnings (I corrected the _date = T error above first).

This came after I commented on an answer to a related question and I am still unsure whether either of the last 3 lines in the snippet is a template specialization or instantiation.

I have also tried to locate the relevant grammar production rule (one allowing template after class) in the C++11 draft published by ISO but came empty handed.

2 Answers

We can see from the following godbolt example this is ill-formed according to clang and MSVC and looking at the draft standard section on Explicit instantiation section [temp.explicit] I don't see any justification for gcc to accepts it.

I believe what the article "possibly" meant given the topic was:

template class Example<int>;
template class Example<float>;
template class Example<double>;

and that indeed is well-formed with gcc/clang/MSVC.

It looks like pre C++11 this grammar was allowed, see defect report 1707: template in elaborated-type-specifier without nested-name-specifier (emphasis mine):

The grammar for elaborated-type-specifier in 10.1.7.3 [dcl.type.elab] reads, in part,

elaborated-type-specifier:
    class-key nested-name-specifieropt templateopt simple-template-id

This allows use of the template keyword without a nested-name-specifier, e.g., struct template S. This is inconsistent with other uses of the template keyword. It might be better to split the production in two and only allow the keyword following a nested-name-specifier,

....

So this makes a little more sense with this comment that -ansi causes a warning.

The other answerer filed two bug reports.

cppreference has a good dicssuion of Explicit instantiation and this SO question Explicit instantiation - when is it used? explains more details why this is useful.

Also note, we can see this Meta post: Links being changed to cppreference.com that the site has been known to have incorrect information and in general the community prefers cppreference as a solid C++ reference.

I see two bugs here:

  1. GCC treats the template keyword here as the template disambiguator, and thus believes that class template Example<int> is equivalent to class Example<int>. This is incorrect because the C++ grammar only permits the template disambiguator to be after ::, . or ->. (C++11 as originally written allows class template Example<int>, but this has been fixed by cwg 1707.)
  2. GCC incorrectly allows a declaration like class Example<int>;. Although class Example<int>; matches the grammar of simple-declaration, it fails to meet the requirement in [dcl.dcl]/5 which states that a simple-declaration must declare or redeclare something (class/enumeration/enumerator/typedef/variable/function).

The former has been reported as GCC bug 87781, the latter as GCC bug 87783.

Update: GCC bug 87781 is now fixed by r266285.

Related