tags:

views:

132

answers:

1

I figured an explicit instantiation request would automatically instantiate all base class members also, but I get a linker error: unresolved external symbol "public: void Base<int>::foo(int)" when building this code using Visual Studio 2008 or 2010.

Note that adding a call to foo() inside bar() forces the compiler to instantiate Base<int>::bar() and the build succeeds, so it appears that the compiler has all the necessary information to instantiate foo().

Obviously, explicitly instantiating Base<int> in source.cpp allows the build to succeed, but it seems silly to need to explicitly instantiate any dependent base classes whenever explicitly instantiating a derived class.

Is this normal? I couldn't find what the standard says regarding this issue.

header.h

template<typename T>
class Base {
public:
    void foo();
};

template<typename T>
class Derived : public Base<T> {
public:
    void bar();
};

source.cpp

#include "header.h"

template<typename T>
void Base<T>::foo() { }

template<typename T>
void Derived<T>::bar() {
    // this->foo();   // adding this forces instantiation of foo()???
}

template class Derived<int>;

main.cpp

#include "header.h"

int main() {
    Derived<int> d;
    d.foo(); // Linker Error: unresolved external symbol "public: void Base<int>::foo(int)"
}

Edit:

It looks like the Standard says only members of a class get instantiated by an explicit class instantiation, so the linker error is justified in my example.

Note that a class is defined by class-head { member-specification } and "The member-specification in a class definition declares the full set of members of the class; no member can be added elsewhere." So members are only between the curly braces { }, and public base class members don't become members of the derived class, they are merely accessible from the derived class or by objects of the derived class.

My only remaining question is why the Standard specifies that explicit instantiation of a class template only instantiates members and not members of base classes? My guess is that this allows greater control of what gets explicitly instantiated where. Someone that's using explicit template class instantiations would most likely have the base class definitions in a different file than the derived class definitions, and would explicitly instantiate each separately.

+3  A: 

The Standard says

The explicit instantiation of a class template specialization implies the instantiation of all of its members not previously explicitly specialized in the translation unit containing the explicit instantiation.

In other words, it does not mandate that base classes are explicitly instantiated in turn. It will cause an implicit instantiation of them which will not instantiate their member definitions up-front. It's some ugly glitch in the Standard as to whether some text when it says "member" means "direct" or "inherited" member, as that often seems to be "obvious" to the one who wrote the Standards wording, but not to the one who reads it. C++0x has added some clarifications (it also has a difference between explicit instantiation declarations and definitions that C++03 doesn't have, but even ignoring that, the C++0x wording contains some more bits of insight):

An explicit instantiation that names a class template specialization is also an explicit instantiation of the same kind (declaration or definition) of each of its members (not including members inherited from base classes) that has not been previously explicitly specialized in the translation unit containing the explicit instantiation, except as described below. [ Note: In addition, it will typically be an explicit instantiation of certain implementation-dependent data about the class. — end note ]

Johannes Schaub - litb
+1. Is there no broader blanket statement they can make, such as that it is indistinguishable from definition/declaration of a class and all its static members? Leaving it open whether the vtable is instantiated is ugliness which they are acknowledging.
Potatoswatter
+1 The Standard confused me by the use of "class template specialization" to mean an entity produced by "explicit instantiation" versus "explicit specialization" using template<>. I suppose not instantiating base members allows greater control of what gets instantiated and where it goes. Base members could be instantiated in a different source file than the derived class.
JohnPS
@Potatoswatter: Don't we only need the declaration of the base class to determine the size of the derived class's vtable during the derived class's instantiation, and the values in its vtable are filled in by the linker? If any called function is not instantiated in some translation unit, then there will be a linker error.
JohnPS
@John: The issue is whether the vtable is considered *used* by the explicit instantiation. In most cases, a class with a vtable has a virtual destructor, which uses the vtable and forces it to be a weakly-defined symbol in that translation unit. A better example would be the `type_info` object returned by the `typeid` operator. You want *all* auxiliary support structures to be defined at the explicit instantiation in the case of building a library.
Potatoswatter
@JohnPS it's an often misunderstood term. A specialization is a class or function that represents one instance of a template for a given set of template arguments. It can be defined explicitly (by the `template<>` syntax) or the specialization can be generated from the template (by instantiation).
Johannes Schaub - litb
@Potatoswatter there is no such thing as a vtable for the Standard, so there needs to be no mention of it by the Standard. All the Standard knows about is a class that has virtual member functions and which are instantiated.
Johannes Schaub - litb
@Johannes: Yes, and the standard is even explicit that there may or may not be a single `type_info` object per class — the compiler is allowed to generate an inline factory function instead. However, they could still be more specific in their wording, as I suggested in the first comment.
Potatoswatter