4

Let's say we have the following files:

foo.h

namespace ns
{
    template <typename T>
    class Foo
    {
    public:
        Foo();

        ~Foo();

        void DoIt();
    };
}

foo.cpp

#include "foo.h"

#include <iostream>

namespace ns
{
    template <typename T>
    Foo<T>::Foo() { std::cout << "Being constructed." << std::endl; }

    template <typename T>
    Foo<T>::~Foo() { std::cout << "Being destroyed." << std::endl; }

    template <>
    void Foo<int>::DoIt()
    {
        std::cout << "Int" << std::endl;
    }

    template <>
    void Foo<double>::DoIt()
    {
        std::cout << "Double" << std::endl;
    }

    template class Foo<int>;
    template class Foo<double>;
}

Is that the correct way to do explicit instantiation, assuming the type will only ever be used with int or double as type parameters? Or do you need to declare the explicit specialization in the header file as well?

Doing it the way I've shown works with visual studio, but a coworker has been having problems with GCC (Although I've just checked, and I think that's due to something else, but I'll post this question anyway)

Bwmat
  • 4,314
  • 3
  • 27
  • 42
  • You'll have to define the destructor as well, since you're declaring it, and move the definitions of the constructor and the destructor to the header since they are templates. As far as it concerns the specializations they are going to be visible only in your `.cpp` file. – 101010 Apr 14 '15 at 19:23
  • @101010 No need to move c/dtor to the header, there's an explicit instantiation. – T.C. Apr 14 '15 at 19:26
  • @T.C. In deed no need to move them to the header in order for this example to work. However, since they are templates I would move them to the header, as part of good practice. – 101010 Apr 14 '15 at 19:29
  • Forgot about the destructor, thanks for pointing it out. – Bwmat Apr 14 '15 at 19:29
  • @101010 - One of the assumptions here is that the set of types to be used as type parameters for the template is well known, and finite. – Bwmat Apr 14 '15 at 19:30

1 Answers1

5

[temp.expl.spec]/p6 (emphasis mine):

If a template, a member template or a member of a class 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.

In fact, if you combine them inside a single TU, both clang and gcc will issue an error. You need to declare these explicit specializations.


And since we are really close to it, I'll just quote [temp.expl.spec]/p7 as well, because I can:

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.

T.C.
  • 133,968
  • 17
  • 288
  • 421
  • The whole point of only declaring the template in the header, and moving all of the implementation (specialized or not) into the cpp file was to avoid implicit instantiation. Without that, that excerpt doesn't apply? – Bwmat Apr 14 '15 at 19:27
  • @Bwmat Calling the function triggers an implicit instantiation of the declaration. – T.C. Apr 14 '15 at 19:28
  • ***..., etc.***?? WTF? :-) – alain Apr 14 '15 at 19:39
  • 2
    @alain The last line is a limerick. The previous text was inserted to hide it. – dyp Apr 14 '15 at 19:41
  • 3
    @dyp A *normative* limerick, too. – T.C. Apr 14 '15 at 19:42
  • Why don't you mention explicit instantiation declarations (`extern template`)? – dyp Apr 14 '15 at 19:43
  • Thanks @dyp, I was really thinking it's a quote from the standard. I would not be very surprised to find something like this there ;-) – alain Apr 14 '15 at 19:44
  • 1
    @alain It **is** a quote from the Standard. The Standard contains this limerick (and the text hiding it). – dyp Apr 14 '15 at 19:44
  • @dyp With the current code structure in the OP, I don't think an `extern template` adds much (if at all). – T.C. Apr 14 '15 at 19:54
  • I thought you had to use `extern template` to use those instantiations in a translation unit != `foo.cpp`? – dyp Apr 14 '15 at 19:56
  • @dyp No, it just saves you extra instantiations. – T.C. Apr 14 '15 at 19:56
  • I'm a bit confused: The Standard says (IMHO a bit vaguely) that odr-use of a function causes its *instantiation*. It does not say what this instantiation does (instantiate the definition or declaration?). If the definition of a function template is not available in a TU, current g++ and clang++ do *compile* a TU that implicitly instantiates it, but fail when linking (whether or not there is an explicit instantiation declaration). They accept a program that contains any kind of instantiation for the same set of templ args in another TU. Is this legal? – dyp Apr 14 '15 at 20:08
  • 1
    @dyp [temp]/6: "A function template, member function of a class template, variable template, or static data member of a class template shall be defined in every translation unit in which it is implicitly instantiated (14.7.1) unless the corresponding specialization is explicitly instantiated (14.7.2) in some translation unit; no diagnostic is required." – T.C. Apr 14 '15 at 20:11