Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Linkage of explicit class template instantiation

Are multiple instantiations of the same class template with the same type allowed in different compilation units? What about function templates?

A sample code is as follow:

test.hpp

template <typename T>
class A
{
    public:
        T out();
};

template <typename T>
T A<T>::out()
{
    return T(1);
}

test1.cpp

#include "test.hpp"
template class A<int>;
int testFn()
{
    return A<int>().out();
}

test2.cpp

#include "test.hpp"
template class A<int>;
extern int testFn();
int main()
{
    return testFn() == A<int>().out();
}

If I run

g++ -std=c++11 test1.cpp test2.cpp -o test

it compiles without complaining duplicated definitions.

I was refering to old drafts of standard [1][2], and assuming linkage part doesn't change too much (except for anonymous namespaces). The class template has external linkage by 3.5p4 and 14p4. If that's the case, I would expect that g++ should complain duplicated definitions of A::out(). Am I missing something here?

What if test.hpp defines a function template without "static" or "inline" instead?

Thank you.

[1] http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2798.pdf [2] http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf

like image 591
nocte107 Avatar asked May 29 '15 06:05

nocte107


1 Answers

A good way to find the answers to these questions in the implementation is to use "nm." Often the mangled C++ symbols are more readable if you pipe the output of nm to c++filt.

For example if you compiled with "-c" to make ".o"s of each compilation unit, then you can run nm. When I do this I see that the template members are weak symbols "W" code (on x86 linux). That means that multiple definitions are ok, and in some system specific manner. If I make a function that is non templatized, it will appear as a "T" in both translation units corresponding object files. That will cause a multiple defined symbol.

Usually C++ templates are instantiated on an as needed basis (without a full instantiation) which would allow you to use an _impl type header in addition to the declaration header.

You are not really allowed to define a member template as static (that will give an error). You can define it as inline. In that case, you will not see any symbol for the member template using nm, because it has been inlined.

like image 198
aselle Avatar answered Oct 13 '22 10:10

aselle