Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Linker error with implicit instantiation of private C++ template with LLVM-Clang

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.

like image 966
floriang Avatar asked Feb 12 '23 14:02

floriang


1 Answers

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.

like image 117
n. m. Avatar answered Apr 05 '23 23:04

n. m.