I have a project with configuration:
./main.cpp
./type_traints/TypeTraints.cpp
./type_traints/TypeTraints.hpp
./type_traints/chapter_20.hpp
The ./type_traints/CMakeLists.txt file is:
cmake_minimum_required (VERSION 2.8)
add_library(chapter_20 TypeTraints.cpp)
and the ./CMakeLists.txt follows:
cmake_minimum_required (VERSION 2.8)
project (mpl)
add_subdirectory(type_traints)
include_directories(type_traints)
link_directories(type_traints)
add_executable (mpl main.cpp)
target_link_libraries(mpl chapter_20)
Relevant parts of files (most includes omitted) include:
./type_traints/chapter_20.hpp
#ifndef CHAPTER_20_GUARD
#define CHAPTER_20_GUARD
#include <TypeTraints.hpp>
void chapter_20() {
test_23();
}
#endif //CHAPTER_20_GUARD
./type_traints/TypeTraints.hpp
#ifndef TYPE_TRAINTS_GUARD
#define TYPE_TRAINTS_GUARD
namespace details {
template<class T> const char* class2name() {
return "unknown";
};
template<> const char* class2name<int>() {
return "int";
};
}
template<class T>
class type_descriptor {
friend std::ostream& operator << (std::ostream& stream,
const type_descriptor<T>& desc) {
stream << desc.getName();
return stream;
}
public:
std::string getName() const;
};
template<class T>
std::string type_descriptor<T>::getName() const {
return details::class2name<T>();
}
void test_23();
#endif // TYPE_TRAINTS_GUARD
./type_traints/TypeTraints.cpp
#include<TypeTraints.hpp>
void test_23() {
cout << type_descriptor<int>() << endl;
}
and ./main.cpp
#include <chapter_20.hpp>
int main(int argc, char* argv[]) {
chapter_20();
return 0;
}
The project compiles but fails to link:
[ 50%] Building CXX object type_traints/CMakeFiles/chapter_20.dir/TypeTraints.cpp.o
Linking CXX static library libchapter_20.a
[ 50%] Built target chapter_20
[100%] Building CXX object CMakeFiles/mpl.dir/main.cpp.o
Linking CXX executable mpl
type_traints/libchapter_20.a(TypeTraints.cpp.o): In function `char const* details::cl
ass2name<int>()':
/home/marcin/Projects/mpl/type_traints/TypeTraints.hpp:312: multiple definition of `c
har const* details::class2name<int>()'
CMakeFiles/mpl.dir/main.cpp.o:/home/marcin/Projects/mpl/type_traints/TypeTraints.hpp:
312: first defined here
collect2: ld returned 1 exit status
make[2]: *** [mpl] Błąd 1
make[1]: *** [CMakeFiles/mpl.dir/all] Error 2
make: *** [all] Error 2
23:56:20@marcin-laptop ~/P
The project links fine if I remove the class2name specialization (class2name<int>()) from TypeTraints.hpp and use only the generic implementation.
Does anybody have an idea Why is that? Did I miss-configure cmake files?
In short: an explicitly (i.e. fully) specialized template function is no longer a template. It is an ordinary function and it obeys One Definition Rule for ordinary functions.
In other words you can't define explicitly specialized function templates in header file. Doing so will result in ODR violations.
A template is a template only as long as it depends on at least one parameter. I.e. partial specializations can be defined in header files (since they are still templates). Explicit (i.e. full) specializations can only be declared in header files, but have to be defined in implementation files, just like ordinary functions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With