C++:避免重复符号链接器错误

3

我遇到了链接器错误:

duplicate symbol __ZN5ENDF64FileILNS_7MF_enumE1EE4readEv in:
    Read.cpp.o
    Material.cpp.o

当重复的符号名称为:

$ c++filt __ZN5ENDF64FileILNS_7MF_enumE1EE4readEv
  ENDF6::File<(ENDF6::MF_enum)1>::read()

我知道在多个地方定义相同的函数会导致链接错误。这是可能会发生的情况。(我看到了这个问题:ld: duplicate symbol) 我不认为我在多个地方定义了read()函数,但链接器(clang++)却说我有。
我的代码结构如下:
//MFs.hpp
#ifndef MFS_HPP
#define MFS_HPP
enum class MF_enum {
...
}
#endif


//File.hpp
#ifndef FILE_HPP
#define FILE_HPP

#include "MFs.hpp"

// Definition of class File
template<>
class File {
...
}

// Definition of File<...>::read() function
template <>
void File<1>::read()
{
    std::cout << "Reading into MF=1"<< std::endl;
}

#endif

File.cpp不存在,因为File类是一个模板类。所有的定义(和声明)都在File.hpp中。

// Material.cpp
#include "File.hpp"
...

// Material.hpp
#ifndef MATERIAL_HPP
#define MATERIAL_HPP

#include "File.hpp"
...
#endif

最后是驱动程序代码:
// Read.cpp
#include "Material.hpp"
#include "File.hpp"

int main (){
...
}

3
你是否专门处理File<1>::read()?如果是的话,你需要将该特化标记为inline(完全特化不再是模板,而是一个函数。[实际上定义read函数是这个问题的核心,它不应该被隐藏在注释中:// Definition of File<...>::read()!!!] - David Rodríguez - dribeas
你是否在 MFs.hpp 中包含了 #include "MFs.hpp"? - Ram
你是否在头文件中定义了 read() 函数的声明和实现?如果是(且该函数没有被内联),可能会导致链接错误。 - Mine
1
@DavidRodríguez-dribeas 如果他有一个包含保护,为什么还会导致重复符号? - David G
1
@0x499602D2:不同的翻译单元加载相同的头文件,每个翻译单元只会看到一次定义,但它将生成符号。链接器将因为符号在多个翻译单元中被定义而失败。包含保护可以防止在单个翻译单元中看到两次相同的头文件,但不能防止不同的翻译单元定义相同的符号。 - David Rodríguez - dribeas
显示剩余2条评论
1个回答

7

一个模板的完整特化本身不是模板。如果你要对函数进行特化,那么你需要将其只声明在头文件中,并在单个翻译单位中提供实现,或者定义为内联:

// Header [1]
template <int>
class File {
   // ...
   void open();
};
template <>
void File<1>::open(); // just declaration

// Single .cpp
template <>
void File<1>::open() { ... }

或者:

// Header [2]
template <int>
class File {
   // ...
   void open();
};
template <>
inline void File<1>::open() { ... }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接