我有一个配置项目:
./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
./ 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
如果从TypeTraints.hpp中删除class2name特化(class2name<int>()
)并仅使用泛型实现,则项目链接正常。
有人知道为什么会这样吗?我错过了配置cmake文件吗?
答案 0 :(得分:9)
简而言之:明确(即完全)专用模板函数不再是模板。它是一个普通的函数,它遵循普通函数的一个定义规则。
换句话说,您无法在头文件中定义明确的专用函数模板。这样做会导致ODR违规。
模板只是一个模板,只要它至少依赖于一个参数。即部分特化可以在头文件中定义(因为它们仍然是模板)。 显式(即完整)特化只能在头文件中声明,但必须在实现文件中定义,就像普通函数一样。< / p>
答案 1 :(得分:3)
这违反了一个定义规则:
可以有多个定义 类的类型(第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>()
定义移动到实现文件中应该可以解决问题。我也认为你应该看看"Why not specialize function templates ?"。
答案 2 :(得分:1)
您的档案:
./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文件)中。编译后这两个文件将链接在一起,这会导致多重定义链接错误。