Alex Rivera | Logout

Does extern template prevent inlining of functions?

Asked 2011-07-17T19:46:33.883
33

I'm not entirely clear on how the new extern template feature is meant to work in C++11. I understand that it is intended to help speed up compilation time, and simplify linking issues with shared libraries. Does that mean that the compiler does not even parse the function body, forcing a non-inlined call to be made? Or does it simply instruct the compiler to not generate an actual method body when a non-inlined call is made? Obviously, link-time code generation not withstanding.

As a concrete example of where the difference might matter, consider a function that operates on an incomplete type.

//Common header
template<typename T>
void DeleteMe(T* t) {
    delete t;
}

struct Incomplete;
extern template void DeleteMe(Incomplete*);

//Implementation file 1
#include common_header
struct Incomplete { };
template void DeleteMe(Incomplete*);

//Implementation file 2
#include common_header
int main() {
   Incomplete* p = factory_function_not_shown();
   DeleteMe(p);
}

Within "Implementation file 2", it is unsafe to delete a pointer to Incomplete. So an inlined version of DeleteMe would fail. But if it is left as an actual function call, and the function itself were generated within "Implementation file 1", everything will work correctly.

As a corollary, are the rules the same for member functions of templated classes with a similar extern template class declaration?

For experimental purposes, MSVC produces the correct output to the above code, but if the extern line is removed generates a warning about deleting an incomplete type. However, this is the remnants of a non-standard extension they introduced years ago so I'm not sure how much I can trust this behavior. I don't have access to any other build environments to experiment on [save ideone et al, but being limited to one translation unit is rather limiting in this ca

Edit
Report

1 Answer

8

The idea behind extern templates is to make explicit template instantiations more useful.

As you know, in C++03, you can explicitly instantiate a template using this syntax:

template class SomeTemplateClass<int>;
template void foo<bool>();

This tells the compiler to instantiate the template in the current translation unit. However, this doesn't stop implicit instantiations from happening: the compiler still has to perform all implicit instantiations and then merge them together again during linking.

Example:

// a.h
template <typename> void foo() { /* ... */ }

// a.cpp
#include "a.h"
template void foo<int>();

// b.cpp
#include "a.h"
int main()
{
    foo<int>();
    return 0;
} 

Here, a.cpp explicitly instantiates foo<int>(), but once we go to compile b.cpp, it will instantiate it again because b.cpp has no idea that a.cpp is going to instantiate it anyway. For large functions with many different translation units doing implicit instantiations, this can add quite significantly to compile and link time. It may also cause the function to be unnecessarily inlined, which can lead to significant code bloat.

With extern templates, you can let other source files know that you plan to instantiate the template explicitly:

// a.h
template <typename> void foo() { /* ... */ }
extern template void foo<int>();

This way, b.cpp won't cause an instantiation of foo<int>(). The function will be instantiated in a.cpp and will be linked like any normal function. It's also much less likely to be inlined.

Note that this doesn't prevent inlining -- the function could still be inlined at link time in exactly the same way that a normal non-inline function can still be inlined.

EDIT: Fo

answered 2011-07-17T20:41:55.703

Your Answer