3

I'm getting a linker error:

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

where the duplicate symbol name is:

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

I know that I can't define the same function in multiple places—that's what can cause this linker error. (I've seen this question: ld: duplicate symbol) I don't think I have the read() function defined in multiple places, but the linker (clang++) says I do.

Where am I duplicating the read() symbol?

My code structure looks like this:

//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

There is no File.cpp because the File class is templated. All definitions (and declarations) are in File.hpp

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

// Material.hpp
#ifndef MATERIAL_HPP
#define MATERIAL_HPP

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

Finally the driver code:

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

int main (){
...
}
Community
  • 1
  • 1
jlconlin
  • 14,206
  • 22
  • 72
  • 105
  • 3
    Are you specializing `File<1>::read()`? If so, you need to mark the specialization `inline` (full specializations are no longer a template, but a function. [The actual definition of the `read` function is the core of this question, it should not be hidden in a comment: `// Definition of File<...>::read()`!!!] – David Rodríguez - dribeas Apr 29 '14 at 13:59
  • Are you including #include "MFs.hpp" within MFs.hpp ? – Ram Apr 29 '14 at 14:00
  • @Ram: If that was the case, and include guards did not work, it would trigger a compiler, not linker, error. – David Rodríguez - dribeas Apr 29 '14 at 14:01
  • Did you define the `read()` function not only the declaration, but also the implementation in the header file? If so (and if the function is not inlined) it may cause link error. – Mine Apr 29 '14 at 14:05
  • @DavidRodríguez-dribeas Yes, I did specialize the `File<1>::read()`. I didn't know the specialization would cause the problem. When I add the `inline` keyword, it links without a problem. If you create an answer, I'll accept it. Thanks! – jlconlin Apr 29 '14 at 14:11
  • 1
    @DavidRodríguez-dribeas If he has an include guard why does it still cause a duplicate symbol? – David G Apr 29 '14 at 14:23
  • 1
    @0x499602D2: Different translation units load the same header, each one of them will see the definition only once, but it will generate the symbol. The linker will then fail as the symbol is defined in multiple translation units. Include guards protect from seeing the same header twice in a single translation unit, not from different translation units defining the same symbol. – David Rodríguez - dribeas Apr 29 '14 at 14:26

1 Answers1

7

(Complete) specializations of a template are not templates themselves. If you are specializing the function, then you need to either just declare it in the header and provide the implementation in a single translation unit, or else make the definition inline:

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

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

Alternatively:

// Header [2]
template <int>
class File {
   // ...
   void open();
};
template <>
inline void File<1>::open() { ... }
David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489