10
votes

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

1
[temp.spec]p5 "For a given template and a given set of template-arguments, — an explicit instantiation definition shall appear at most once in a program [...] An implementation is not required to diagnose a violation of this rule."dyp
See also CWG NAD 1045 which contains a reason why this probably not diagnosed.dyp
@dyp, In this case, my program actually violates 14.7.0.5, but the standard says g++ is not required to diagnose this and actually g++ solved the multiple definition. But to have it standard-compliant, I should define all the instantiations in only one translate unit and declare ("extern") explicit template instantiation in other translation units. Am I correct?nocte107
I guess so, although I don't quite understand the purpose of this requirement for a) class template specializations b) function template specializations that are either inline or have internal linkage.dyp
@dyp, Then it blows my mind. Basically whatever C++ code I have written is wrong. I should have add extern template class std::vector<int> all the time.nocte107

1 Answers

3
votes

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.