5

Disclaimer: I know that templates are usually implemented in the header file. Please read through.

I have a C++ template-related issue. My code builds with MSVC under Windows but doesn't with LLVM-Clang under Mac OSX, but I'm not sure which one is wrong.

Here is a simple test case, composed of three source files:

  • main.cpp

    #include "templ.h"
    
    int main()
    {
       templ(1);
       return 0;
    }
    
  • templ.h

    template<typename T>
    T templ(const T&);
    
  • templ.cpp

    #include "templ.h"
    
    template<typename T>
    T templ(const T& t)
    {
       return t;
    }
    
    //explicit instantiation
    template int templ(const int&);
    
    //implicit instantiation
    void f()
    {
       templ(1);
    }
    

As you can see, I want the implementation of the function template to be private (i.e. hidden in the .cpp file). To allow this, I must instantiate my template in the same translation unit as its definition. In the above example, I only instantiate templ<int>. AFAIK, this is unusual, but perfectly cromulent C++.

As is, this code builds with both the compilers. However, if I comment out the explicit instantiation and only leave the implicit instantiation, the compilers behave differently. MSVC builds successfuly, but LLVM-Clang fails with the following linker error:

Undefined symbols for architecture x86_64:
  "int templ<int>(int const&)", referenced from:
      _main in main.cpp.o
ld: symbol(s) not found for architecture x86_64

Besides, that error occurs only when the optimization is enabled (e.g. -02).

What does the standard say about this? Is this a known behavior/bug of LLVM-Clang?

My version of LLVM-Clang is:

Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)
Target: x86_64-apple-darwin13.0.0
Thread model: posix

Sorry if this is a duplicate. It's very hard to pick the correct keywords.

floriang
  • 139
  • 1
  • 7
  • http://stackoverflow.com/q/495021/819272 – TemplateRex Jul 03 '14 at 12:29
  • @TemplateRex, this question doesn't help. I know how template instantiation works. Besides, the statement quoted in the question is wrong, as pointed by answers dealing with explicit instantiation. – floriang Jul 03 '14 at 12:46
  • you should read the answer by @Ben in the linked question – TemplateRex Jul 03 '14 at 13:09
  • @TemplateRex, Ben's answer doesn't help either. The mechanism he describes doesn't state the way I use the templates is wrong. Au contraire, he even says that "If foo.cpp itself uses MyClass, then code for that will be generated while compiling foo.cpp, so when bar.o is linked to foo.o they can be hooked up and will work." This is exactly what I do! – floriang Jul 03 '14 at 13:43
  • "So when foo.cpp is compiled [...] the compiler can't see bar.cpp to know that MyClass is neede but it can't see the template MyClass (only its interface in foo.h) so it can't create it.". Replace his `bar.cpp` and `foo.cpp` with your `main.cpp` and `templ.cpp`. This explains why the call `templ(1)` cannot be compiled because the missing implementation is in `templ.cpp`. The epxlicit instantiation in `foo.cpp` will make `templ(1)` visible to the linker, but implicit instantiation won't. – TemplateRex Jul 03 '14 at 13:52
  • What I see in practice is that MSVC does make templ visible to the linker. Do does LLVM in -O0 mode. Whether the difference between an explicit and an implicit instantiation matters according to the standard is at least debatable. So why downvoting and marking my question as duplicate in this case? – floriang Jul 03 '14 at 14:09
  • I still think it's a borderline dupe, but have reopened it for you anyway. You might also want to check http://stackoverflow.com/questions/21534435/separate-compilation-and-template-explicit-instantiation – TemplateRex Jul 03 '14 at 14:12
  • Have you tried adding an explicit instantiation declaration to `templ.h` (matching the explicit instantiation definition in `templ.cpp` ? – Jonathan Wakely Jul 03 '14 at 14:23
  • @JonathanWakely wouldn't that give an ODR violation? – TemplateRex Jul 03 '14 at 14:26
  • @TemplateRex, no because it would only be a _declaration_ not a definition. But I missed the part of the question about commenting out the explicit instantiation ... that's not ok. – Jonathan Wakely Jul 03 '14 at 16:20

1 Answers1

9

This is normal and expected.

14 Templates
6 A function template, member function of a class template, variable template, or static data member of a class template shall be defined in every translation unit in which it is implicitly instantiated (14.7.1) unless the corresponding specialization is explicitly instantiated (14.7.2) in some translation unit; no diagnostic is required.

As applied to your case, this means that when the explicit instantiation of templ is removed, the compiler can either

  1. generate an instantiation normally because of the implicit instantiation in the same TU; or
  2. inline the call to templ and not generate any externally usable entity.

Either behaviour is permitted for a conforming implementation. If you make sure there's an explicit instantiation somewhere, either will produce valid object code. If you don't, you may or may not get an error and it's your own fault.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243