Intel® oneAPI Base Toolkit
Support for core tools and libraries to build and deploy high-performance data-centric applications
316 Discussions

Error when linking static library which contains explicit template instantiation

stefa
Beginner
1,098 Views

 

I get following linking errors when trying to compile simple test program with ICX which calls templatized class from a static library. 

 

main.cpp.obj : error LNK2019: unresolved external symbol "public: __cdecl TestLib<float>::TestLib<float>(void)" (??0?$TestLib@M@@QEAA@XZ) referenced in function main
main.cpp.obj : error LNK2019: unresolved external symbol "public: void __cdecl TestLib<float>::print(void)" (?print@?$TestLib@M@@QEAAXXZ) referenced in function main
TemplateProject.exe : fatal error LNK1120: 2 unresolved externals

 

Here is the CMakeLists.txt of the test project:

 

cmake_minimum_required(VERSION 3.20)

project(TemplateProject LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_library(TestLib STATIC TestLib.h TestLib.cpp)

add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME} PUBLIC TestLib )

 

TestLib.h 

 

// TestLib.h

#include <iostream>
template <class RealType>
class TestLib {
 public:
  TestLib();
  void print();
};

 

TestLib.cpp

 

// TestLib.cpp
#include "TestLib.h"

template class TestLib<float>;
template class TestLib<double>;

template <class RealType>
TestLib<RealType>::TestLib() {}

template <class RealType>
void TestLib<RealType>::print() {
  RealType i{0};
  std::cout << "Hallo from the print function! " << i << "\n";
}

 

and the main.cpp

 

// main.cpp

#include "TestLib.h"

int main() {
  TestLib<float> a;
  a.print();
  return 0;
};

 

 Having explicit explicit template instantiation is a common practice when having function definitions in .cpp files, and this piece of code works just fine with MSVC 16 compiler as well as with GCC 9. 

I tested this on Windows using :

Intel(R) oneAPI DPC++/C++ Compiler for applications running on Intel(R) 64, Version 2021.4.0 Build 20210924 

0 Kudos
1 Solution
Viet_H_Intel
Moderator
1,031 Views

Try to rearrange test.cpp. Basically put template class explicit instantiations below anything else.


https://en.cppreference.com/w/cpp/language/class_template


template <class RealType>

TestLib<RealType>::TestLib() {}


template <class RealType>

void TestLib<RealType>::print() {

 RealType i{0};

 std::cout << "Hallo from the print function! " << i << "\n";

}


template class TestLib<float>;

template class TestLib<double>;


Thanks,



View solution in original post

6 Replies
NoorjahanSk_Intel
Moderator
1,046 Views

Hi,


Thanks for reaching out to us.


We are also able to reproduce the issue from our end.

We are working on it. We will get back to you soon.


Meanwhile, you can try compiling your code with icl compiler.


Thanks & Regards,

Noorjahan.



Viet_H_Intel
Moderator
1,032 Views

Try to rearrange test.cpp. Basically put template class explicit instantiations below anything else.


https://en.cppreference.com/w/cpp/language/class_template


template <class RealType>

TestLib<RealType>::TestLib() {}


template <class RealType>

void TestLib<RealType>::print() {

 RealType i{0};

 std::cout << "Hallo from the print function! " << i << "\n";

}


template class TestLib<float>;

template class TestLib<double>;


Thanks,



stefa
Beginner
1,015 Views

Thanks a lot! This trick did the work. However shouldn't this be still labeled as compiler bug? Standard does not require specialization to be at the end of the cpp file.

Viet_H_Intel
Moderator
952 Views

Hi,


This issue also occurs with LLVM compiler as well. Let me work with our Front End team and get back to you when I have an update.


Thanks,

Viet


Michoumichmich
Beginner
689 Views

Hello, 

This is not a compiler bug. C++ is parsed from top to bottom and at the moment when you instantiate your template in the .CPP, the only definition the compiler sees is the one in the header. So your instantiation cannot instantiate the template yet. 

 

Furthermore when instantiating a template somewhere you should declare that in the header:

extern template class TestLib<float>; 

Otherwise it would be "reinstantiated" without your specialisation somewhere else and you would break the One Definition Rule. 

 

Best, 

Michel

Viet_H_Intel
Moderator
408 Views

After some discussion in community we realized Clang’s behavior is correct per spec. There is an ABI incompatibility with the other compilers, but fixing that requires an ABI break and given the trivial workaround of defining the class before instantiating it, so there’s almost no chance the ABI break is worth it.

We will close this case as wont fix.

Thanks,


Reply