0

nice to meet you, Stack overflow residents! Have a question: I'm using Visual Studio 2019 that says me that I've defined some methods multiple times.

I have a header file (for example):

// header.hpp
#ifndef HEADER_HPP
#define HEADER_HPP

#include <iostream>

struct a {
    a();
};
#include "degradation.inl"

#endif HEADER_HPP

And the .inl file for definitions (for example):

// degradation.inl
a::a() {
    cout << "the hopless one\n";
}

So, the problem is, when I include this with #include <header.hpp> (that is, I've configured the include paths), have something that looks like that (for example):

error LNK2005: "public: __cdecl a::a(void)" (s0mEsтR@njeSуМb0ls) already defined in helpme.obj

Well, it's not the actual code (you can find the actual code here: GitHub), but I think that this code is a good example.

  • This technique works for class templates where the implementation must be in the header. For regular classes you will violate the ODR if more than 1 source file includes the .inl file. Because each source file that includes the .inl has a definition. There is a way around this but its better to just make the .inl file a .cpp file and don't include it from the header. – drescherjm Jan 30 '21 at 15:40
  • Should I make it header-only? Cause, I think, it's not a good idea to write .cpp files in libraries – Alex Porubaimikh Jan 30 '21 at 15:47
  • You need to use `inline` for function definitions which appear in header files. Otherwise you'll have the function definition in every compilation unit seen by the linker, and it doesn't know which one to use (lookup the One Definition Rule). – πάντα ῥεῖ Jan 30 '21 at 15:47

2 Answers2

1

A #include is logically equivalent to inserting the entire contents of the included file into the file that includes it. It's exactly as if the contents of the included file were present in the file that included it. And this applies recursively.

If you work out, on paper and pencil, what happens here, this means that every .cpp that #includes what's shown will define a::a(), and compile it as part of the .cpp.

That is the reason for your duplicate symbol when linking. The simplest solution is to simply move the definition of a::a() into its own, separate, .cpp file. Don't #include it from any header, just compile and link it together with the rest of your .cpp files.

Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148
1

Just change

a::a() {
    cout << "the hopless one\n";
}

to

inline a::a() {
    cout << "the hopless one\n";
}

If you define functions in header files they should be inline (templates are an exception).

john
  • 85,011
  • 4
  • 57
  • 81