14

I (vaguely) know that a template is not instantiated if it is not used. For example, the following code will compile fine even though T::type doesn't make sense when T = int.

template<typename T>
struct A
{
    void f() { using type = typename T::type; }
};

A<int> a; //ok

It compiles because f() is not used, so it is not instantiated — thus the validity ofT::type remains unchecked. It doesn't matter if some other member function g() calls f().

template<typename T>
struct A
{
    void f() { using type = typename T::type; }

    void g() { f(); } //Is f() still unused?
};

A<int> a; //ok

This also compile fines. But here I realize the vagueness in my understanding of the definition of "use". I ask:

  • Is f() still unused? How exactly?

I can clearly see it being used inside g(). But then I thought since g() is not used, f() is not used either, from instantiation point of view. That seems reasonable enough. so far.

However if I add virtual keyword to g(), it doesn't compile:

template<typename T>
struct A
{
    void f() { using type = typename T::type; }

    virtual void g() { f(); } //Now f() is used? How exactly?
};

A<int> a; //error

It results in compilation error because now it attempts to instantiate f(). I don't understand this behavior.

Could anybody explain this? Especially the impact of virtual keyword on the definition of "use" of member of class template.

Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • 1
    If I recall correctly, `virtual` forces instantiation of the member function because it is now nigh-impossible to statically assess whether this function will be used or not. In practice, you are asking to create a v-table filled with pointers to functions... so the function need exist so we can take a pointer to it. – Matthieu M. Oct 28 '13 at 08:36
  • The struct template only gets instantiated when you use it. It is either the entire struct or nothing. It doesn't have anything to do with g or f. – Sarien Oct 28 '13 at 08:36
  • 1
    @Sarien: it does, member functions of a template class are only instantiated if ODR-used. – Matthieu M. Oct 28 '13 at 08:37
  • @Sarien: That would be really stupid to instantiate all the members even if you don't use them. Fortunately, C++ is smart and instantiates *only* what you use. – Nawaz Oct 28 '13 at 08:38

1 Answers1

10

A quick look at 3.2 [basic.def.odr] yields:

3/ [...] A virtual member function is odr-used if it is not pure. [...]

And I also found at 14.7.1 [temp.inst]:

10/ 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. It is unspecified whether or not an implementation implicitly instantiates a virtual member function of a class template if the virtual member function would not otherwise be instantiated. (emphasis mine)

So... I would say it is likely that a virtual method will always be instantiated.

In pragmatic terms, I would expect a compiler to instantiate the virtual table of a template class when it instantiates the class; and thus immediately instantiate all virtual member functions of this class (so it can references those from the virtual table).

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722