Is it valid for a C++ compiler to implicitly instantiate ALL member functions of a template class?

c++, c++11, c++builder, windows

Solution

If a template class is used, then all member functions of the class should be implicitly instantiated - whether used or not?

No, this is definitely not the case. Per Paragraph 14.7.1/10 of the C++11 Standard (and Paragraph 14.7.1/9 of the C++03 Standard) very clearly specifies:

An implementation shall not implicitly instantiate a function template, a member template, a non-virtual member function, a member class, or a static data member of a class template that does not require instantiation.

As for when instantiation is required, Paragraph 14.7.1/2 specifies:

Unless a member of a class template or a member template has been explicitly instantiated or explicitly specialized, the specialization of the member is implicitly instantiated when the specialization is referenced in a context that requires the member definition to exist; [...]

This is certainly not the case if a member function is never referenced.

Unfortunately, I can't provide an official reference on what the rules were before C++03, but to the best of my knowledge the same "lazy" instantiation mechanism was adopted in C++98.

Problem

Suppose I have a public class and a private implementation class (e.g. PIMPL pattern), and I wish to wrap the private class with a template smart pointer class with a checked delete, as follows: `PublicClass.h` ``` class PrivateClass; // simple smart pointer with checked delete template<class X> class demo_ptr { public: demo_ptr (X* p) : the_p(p) { } ~demo_ptr () { // from boost::checked_delete: don't allow compilation of incomplete type typedef char type_must_be_complete[ sizeof(X)? 1: -1 ]; (void) sizeof(type_must_be_complete); delete the_p; } private: X* the_p; }; // public-facing class that wishes to wrap some private implementation guts class PublicClass { public: PublicClass(); ~PublicClass(); private: demo_ptr<PrivateClass> pvt; }; ``` `PublicClass.cpp` ``` #include "PublicClass.h" class PrivateClass { public: // implementation stuff goes here... PrivateClass() {} }; //--------------------------------------------------------------------------- PublicClass::PublicClass() : pvt(new PrivateClass()) {} PublicClass::~PublicClass() {} ``` `main.cpp` ``` #include "PublicClass.h" int main() { PublicClass *test = new PublicClass(); delete test; return 0; } ``` This code compiles successfully on Visual C++ 2008, but fails to compile on an old version of C++ Builder. In particular, `main.cpp` does not compile because `demo_ptr<PrivateClass>::~demo_ptr` is being instantiated by `main.cpp`, and that destructor won't compile because it can't do `sizeof` on an incomplete type for `PrivateClass`. Clearly, it is not useful for the compiler to be instantiating `~demo_ptr` in the consuming `main.cpp`, since it will never be able to generate a sensible implementation (seeing as how `~PrivateClass` is not accessible). (`PublicClass.cpp` compiles fine on all tested compilers.) My question is: what does the C++ standard say about implicit instantiation of a template class's member functions? Might it be one of the following? In particular, has this changed over the years? - If a template class is used, then all member functions of the class should be implicitly instantiated - whether used or not? - Or: template class functions should only be implicitly instantiated one at a time if actually used. If a particular template class function isn't used, then it shouldn't be implicitly instantiated - even if other template class functions are used and instantiated. It seems clear that the second case is the case today because this same pattern is used with PIMPL and `unique_ptr` with its checked delete, but maybe that was not the case in the past? Was the first case acceptable compiler behavior in the past? Or in other words, was the compiler buggy, or did it accurately follow the C++98 standard, and the standard changed over the years? (Fun fact: if you remove the checked delete in C++ Builder, and have function inlining turned off, the project will happily compile. `PublicClass.obj` will contain a correct `~demo_ptr` implementation, and `main.obj` will contain an incorrect `~demo_ptr` implementation with undefined behavior. The function used will depend on the order in which these files are fed to the linker.) UPDATE: This is due to a compiler bug, as noted by Andy Prowl, which is still not fixed in C++ Builder XE8. I've reported the bug to Embarcadero: bcc32 compiler causes undefined behavior when using std::auto_ptr with PIMPL idiom because template instantiation rules do not follow C++ spec

Original source

Related problems