9

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.

Armen Michaeli
  • 8,625
  • 8
  • 58
  • 95
  • 2
    https://en.cppreference.com/w/cpp/language/class_template#Class_template_instantiation – HolyBlackCat Oct 28 '18 at 11:19
  • 10
    I was often told cplusplus.com is notoriously bad. Now I see why. The person who wrote that article didn't bother checking their code or facts. – StoryTeller - Unslander Monica Oct 28 '18 at 11:23
  • BTW, it's usually good to double check code acceptance with different compilers. For instance, [Clang complains](http://coliru.stacked-crooked.com/a/dcff6a3520db0111) about those "instantiations". – StoryTeller - Unslander Monica Oct 28 '18 at 11:30
  • I am aware of the dubious reputation of cppreference.com, this is partially why I wrote the question. Also, @HolyBlackCat, I have read that page top to bottom three times before posing the question, I could not find anything relevant on that page, is there any particular paragraph you want to refer me to? – Armen Michaeli Oct 28 '18 at 11:40
  • 7
    You got it backwards, cppreference has high quality standards. Cplusplus.com is dubious. – StoryTeller - Unslander Monica Oct 28 '18 at 11:46
  • @amn *"any particular paragraph you want to refer me to"* Yes, `Class template instantiation` paragraph. At least on my machine, clicking that link scrolls the page to said paragraph. – HolyBlackCat Oct 28 '18 at 11:52
  • Darn, I meant cplusplus.com of course, not cppreference.com! The latter is a great resource. I have it on my mind because that's where I have been most of the day. Apologies for the caused confusion, and now I cannot edit the original comment. – Armen Michaeli Oct 28 '18 at 12:18
  • 1
    @HolyBlackCat It does not shed any light whatsoever on the `class template ...` syntax, from what I have gathered. That is not to say I don't appreciate your attention or effort in trying to help me with this! – Armen Michaeli Oct 28 '18 at 12:19
  • 2
    @amn As StoryTeller's link shows, `class template ...` doesn't seem like a valid syntax at all (despite GCC accepting it). Looking at the article linked in your post, they seem to actually mean `template class ...`. The paragraph I linked explains this syntax. – HolyBlackCat Oct 28 '18 at 12:28
  • 1
    GCC seems to ignore this declaration. It even allows `class template Example;` (when `void _data;` is clearly invalid.) – cpplearner Oct 28 '18 at 12:43
  • 1
    If `g++ -std=c++11` ignores the problematic syntax, does it mean it does not enforce standard compliance? I don't have a problem with g++ otherwise allowing extensions, but I thought `-std=c++11` would put it into strict standards compliance mode and otherwise disallow any feature that isn't part of the specified standard? And if it doesn't disallow `class template ...`, could it mean it is *valid* according to C++11? Then again, since Clang in C++11 compliance mode does complain, it may not be? – Armen Michaeli Oct 28 '18 at 14:06
  • @amn I am also really interested in knowing what the c++ standard truly expects. – Stephane Rolland Oct 28 '18 at 14:22
  • @amn `-std=c++??` alone doesn't enforce full standard compliance. But `-std=c++?? -pedantic-errors` does (or at least is supposed to). I smell GCC bug. – HolyBlackCat Oct 28 '18 at 14:43
  • @HolyBlackCat I have been running the GCC 4.9.2 compiler as `g++ --std=c++11 -pedantic ...` to compile the snippet and I don't even get any warnings. `-pedantic-errors` has no effect either -- maybe because it just turns what otherwise would be compiler warnings into errors. Have no possibility to upgrade GCC as of yet, but will update this space when I do, to see if the compiler has gotten wiser about the whole thing. – Armen Michaeli Oct 28 '18 at 15:11
  • You can check that on http://gcc.godbolt.org – HolyBlackCat Oct 28 '18 at 15:12

2 Answers2

11

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.

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
  • Regarding "what the article meant" -- I also think the example from cplusplus.com doesn't seem to be of the best quality as far as C++ examples go, what with the `_date = T` error. The particular way of instantiating template that it displays may have been "standard" before the standard standardized template instantiation and got the quirks out of it. As it stands it's hard to say other than perhaps concluding that if anything, GCC validates it because it allows such syntax by design or by error (a bug). – Armen Michaeli Oct 28 '18 at 15:16
  • @amn it may be an old vestigial incantation ... but using `-pedantic` (which I use) should produce a diagnostic in that case. I will dig into it some more but if this is not already a bug report it should be reported. – Shafik Yaghmour Oct 28 '18 at 15:19
  • I have just used `-ansi` and *now* GCC *does* complain about the `class template ...` lines, with a warning or an error, if either `-pedantic` or `-pedantic-errors` is present, respectively. I find it strange, because as I have learned from [this answer](https://stackoverflow.com/a/46233765/254343) C++ was never standardized by ANSI anyway, so why would the two switches work together for the GCC C++ compiler... – Armen Michaeli Oct 28 '18 at 15:26
  • @amn oh interesting, I still thing it is sill-formed even given the extra information they prodvide via the diagnostic. – Shafik Yaghmour Oct 28 '18 at 15:30
  • @amn IIUC correctly, ISO documents are also ANSI documents, so calling the ANSI standard is technically accurate. – Shafik Yaghmour Oct 28 '18 at 15:36
  • @Oliv Your link says that `-ansi` forces not just any standard, but specifically `-std=c++99`. – HolyBlackCat Oct 30 '18 at 06:32
  • @HolyBlackCat Indeed, I agree with the "just". – Oliv Oct 30 '18 at 08:00
9

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.

cpplearner
  • 13,776
  • 2
  • 47
  • 72
  • I usually link to the SO question that initiated the bug report, this allows someone who find or deals with the bug report to comment directly here. This may be useful b/c the person who filed the bug report may not longer be active etc... so even if the bug report gets updated the answers may not. – Shafik Yaghmour Oct 29 '18 at 19:57