开发者

"multiple definition of..." error for a full specialisation of a template function

开发者 https://www.devze.com 2023-02-01 00:59 出处:网络
I have a project with configuration: ./main.cpp ./type_traints/TypeTraints.cpp ./type_traints/TypeTraints.hpp

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.


This is a violation of the one definition rule :

There can be more than one definition of a class type (clause 9), enumeration type (7.2), inline function with external linkage (7.1.2), class template (clause 14), non-static function template (14.5.5), static data member of a class template (14.5.1.3), member function of a class template (14.5.1.1), or template specialization for which some template parameters are not specified (14.7, 14.5.4) in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements.

An explicit specialization of the class2name template function does not fall in any of these cases. For this reason, I believe that moving class2name<int>() definition into an implementation file should fix the issue. I also think you should have a look on "Why not specialize function templates ?".


Your files:

./main.cpp  
./type_traints/TypeTraints.cpp  
./type_traints/TypeTraints.hpp  
./type_traints/chapter_20.hpp

in which TypeTraints.hpp is directly included in TypeTraits.cpp and indirectly included in main.cpp(through chapter_20.hpp). However, you fully specification template

 template<> const char* class2name<int>() {
     return "int";
 };

is defined in TypeTraints.hpp which be existing in two different compilation units(the above two .cpp file). These two files will be linked together after compilation and this cause the multiple definition link error.

0

精彩评论

暂无评论...
验证码 换一张
取 消