11

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

nocte107
  • 273
  • 2
  • 10
  • 2
    [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 May 29 '15 at 13:39
  • See also [CWG NAD 1045](http://www.open-std.org/JTC1/SC22/WG21/docs/cwg_closed.html#1045) which contains a reason why this probably not diagnosed. – dyp May 29 '15 at 13:48
  • @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 May 29 '15 at 13:56
  • 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 May 29 '15 at 13:58
  • @dyp, Then it blows my mind. Basically whatever C++ code I have written is wrong. I should have add `extern template class std::vector` all the time. – nocte107 May 29 '15 at 14:10
  • The question ["Separate compilation and template explicit instantiation"](http://stackoverflow.com/q/21534435/) suggests that such things actually fail to link on some compiler/platform combinations. I'll try to find out the reason why this is not allowed. – dyp May 29 '15 at 14:13
  • @nocte107 If that's not what you've been doing so far, then why are you using explicit instantiations in the first place? – bogdan May 29 '15 at 14:41
  • @bogdan, Well. I guess I confused myself. I thought implicit instantiation is also affected. So the sample program should be standard-compliant if I make them implicit instantiated, I guess? – nocte107 May 29 '15 at 15:31
  • @nocte107 That is, remove the `template class A;` lines altogether. Yes, that will be fine, that's how templates are used most of the time. – bogdan May 29 '15 at 15:42
  • @bogdan, What's the linkage for implicit instantiation then? I remember C++11.14p4 says all template class member functions have external linkage. If so, isn't that a linkage error by the standard definition? – nocte107 May 29 '15 at 15:53
  • @nocte107 [14p4] says that "A template name has linkage [...]". It can actually have internal linkage. Class member function names have the same linkage as the name of the class of which they are members; the name of the class can have external, internal, or no linkage, depending on where it's declared. See [3.5]. The rules defining which entities can have more than one definition in a program are in [3.2p6]. – bogdan May 29 '15 at 16:50
  • @bogdan, Thanks for the information. That solves my puzzles. I appreciate your help. – nocte107 May 29 '15 at 18:12
  • @nocte107 That being said, I don't think linkage is the problem here. Linkage is about names from different scopes referring to the same entity. What you're worried about is multiple definitions of the same entity, specifically, the class or function resulting from the instantiation of a corresponding template. I think [14.6.4.1p8] addresses that concern: *[...] A specialization for any template may have points of instantiation in multiple translation units. [...]*, with the restrictions in [14.7p5] (partially quoted by dyp above). – bogdan May 29 '15 at 18:19
  • @bogdan, I see. I think I am checking the wrong part of the standard. Thanks a lot. Would you like to contribute an answer? – nocte107 May 29 '15 at 19:02
  • @nocte107 Your original question was answered by dyp in the first two comments, so, if anything, I think that's what should go into an answer. The following comments complement the answer quite nicely, I'd say they're fine where they are. – bogdan May 29 '15 at 20:17

1 Answers1

3

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.

aselle
  • 639
  • 3
  • 5
  • In your answer, you mentioned "in some system specific manner". Does that mean it is not specified by the standard and may not be portable? As for my last question on function templates, I mean more general function templates rather than class member function templates. Thank you. – nocte107 May 29 '15 at 13:26