Ошибка «множественное определение ...» для полной специализации шаблонной функции - PullRequest
2 голосов
/ 21 декабря 2010


У меня есть проект с конфигурацией:

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

Файл ./type_traints/CMakeLists.txt:

 cmake_minimum_required (VERSION 2.8)
 add_library(chapter_20 TypeTraints.cpp)

и ./CMakeLists.txt следующим образом:

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)

Соответствующие части файлов (большинство из них пропущено) включают:
./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
* * 1014. / 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;
}

и ./main.cpp

#include <chapter_20.hpp>

int main(int argc, char* argv[]) {
chapter_20();
  return 0;
}

Проект компилируется, но не связывается:

[ 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

Проект прекрасно работает, если я удалю специализацию class2name (class2name<int>()) из TypeTraints.hpp и использую только обобщенную реализацию.

У кого-нибудь есть идея? Почему это так? Я пропустил-настроить файлы cmake?

Ответы [ 3 ]

9 голосов
/ 21 декабря 2010

Вкратце: явно (то есть полностью) специализированная функция шаблона больше не является шаблоном . Это обычная функция, и она подчиняется одному правилу определения для обычных функций.

Другими словами, вы не можете явно определять шаблоны специализированных функций в заголовочном файле. Это приведет к нарушениям ODR.

Шаблон - это шаблон только в том случае, если он зависит хотя бы от одного параметра. То есть частичные специализации могут быть определены в заголовочных файлах (так как они все еще шаблоны ). Явная (то есть полная) специализация может быть только объявлена ​​ в заголовочных файлах, но должна быть определена в файлах реализации, как обычные функции.

3 голосов
/ 21 декабря 2010

Это нарушение одного правила определения:

Может быть более одного определения типа класса (раздел 9), типа перечисления (7.2), встроенной функции с внешней связью (7.1.2), шаблон класса (пункт 14), шаблон нестатической функции (14.5.5), член статических данных шаблона класса (14.5.1.3), функция-член шаблона класса (14.5.1.1) или специализация шаблона, для которого некоторые параметры шаблона не указаны (14.7, 14.5.4) в программе при условии, что каждое определение отображается в другой единице перевода, и при условии, что определения удовлетворяют следующим требованиям.

Явная специализация шаблонной функции class2name не относится ни к одному из этих случаев.По этой причине я считаю, что перемещение определения class2name<int>() в файл реализации должно решить эту проблему.Я также думаю, что вы должны взглянуть на «Почему бы не специализировать шаблоны функций?» .

1 голос
/ 09 июня 2011

Ваши файлы:

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

, в которых TypeTraints.hpp напрямую включен в TypeTraits.cpp и косвенно включен в main.cpp (через chapter_20.hpp).Однако ваш шаблон спецификации

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

определен в TypeTraints.hpp, который существует в двух разных единицах компиляции (два вышеуказанных файла .cpp).Эти два файла будут связаны вместе после компиляции, и это приведет к ошибке многократного определения ссылки.

...