0

I've been interested in creating a math library for a project I'm working on, so I created a Math.h file with the namespace 'Math' and a 'Vector3' class defined in it. I'm now trying to define some math helper functions in the math namespace involving Vector3:

namespace Math {
    Vector3 Test() {
        return Vector3::Zero;
    }
}

However, when I try including "Math.h" in my main.cpp, and try calling it

Vector3 test = Math::Test();

I get an error in Visual Studio 2019 saying

Severity    Code    Description Project File    Line    Suppression State
Error   LNK2005 "class Vector3 __cdecl Math::Test(void)" (?Test@Math@@YA?AVVector3@@XZ) already defined in Math.obj myproject"

and I'm not sure if there is something I need to do use a class I made inside of a namespace?

JaMiT
  • 14,422
  • 4
  • 15
  • 31
  • The error message is not a compilation error. It is a linker error. Usually caused by defining (implementing) a function in more than one source file in a project. Since you have defined the function in a header file, `#include`ing that header in more than one source file (directly or indirectly) is the cause. Either (1) tag the function inline, or (2) move the definition out of the header file and into a single source file - and only have a declaration of the function the header. – Peter Mar 02 '20 at 03:32
  • For more details about Linker Tools Error LNK2005, I suggest you could refer to the Doc: https://learn.microsoft.com/en-us/cpp/error-messages/tool-errors/linker-tools-error-lnk2005?view=vs-2019 – Jeaninez - MSFT Mar 02 '20 at 05:29
  • See [SimpleMath](https://github.com/microsoft/DirectXTK/wiki/SimpleMath) for an example: [h](https://github.com/microsoft/DirectXTK/blob/master/Inc/SimpleMath.h), [inl](https://github.com/microsoft/DirectXTK/blob/master/Inc/SimpleMath.inl), [cpp](https://github.com/microsoft/DirectXTK/blob/master/Src/SimpleMath.cpp). – Chuck Walbourn Mar 02 '20 at 08:28

1 Answers1

2

If I understand what you're trying to do, you either must define the function in a source (.cpp) file or define it as an inline function in the header file. Otherwise every time your header gets included, you're basically repeating the definition, and that makes the compiler unhappy.

Option #1: inlined in the header:

#ifndef __MYHEADER_H__
#define __MYHEADER_H__

/* ... */

namespace Math {
    inline Vector3 Test() { return Vector3::Zero;}
}

/* ... */
#endif __MYHEADER_H__

Note: inlining doesn't fail because the compiler substitutes the definition's code for any call to Vector3::Test().

Option #2: Put definition in source file file and declaration in header file.:

Header file (e.g.: myheader.h):

#ifndef __MYHEADER_H__
#define __MYHEADER_H__

/* ... */

namespace Math {
   Vector3 Test() ;
}

/* ... */
#endif __MYHEADER_H__

Source file (e.g. myheader.cpp):

#include "my header.h"

namespace Math {
    Vector3 Test() { return Vector3::Zero; }
}

Add the source file to your project/makefile/cmakelists.txt/whatever and you're good to go.

  • You are also repeating the definition when you use `inline`. But without `inline` there may only be one definition (One-Definition-Rule), but with `inline` there may be definitions in each translation unit as long as they are identical. – walnut Mar 02 '20 at 03:31
  • @walnut that's right. Different definitions of the same inline declaration will yield compilation errors. –  Mar 02 '20 at 15:14
  • No, multiple definitions of the same `inline` function which are not identical does generally not cause a compilation error. It makes the program *ill formed, no diagnostic required*. Also "*Note: inlining doesn't fail because the compiler substitutes the definition's code for any call to Vector3::Test().*": That doesn't apply to your shown code. `inline` does *not* mean that function will be inlined. It just means that each translation unit using the function will contain the definition for it. – walnut Mar 02 '20 at 15:43
  • Furthermore, you should avoid using `__MYHEADER_H__` as header guard. Identifiers containing double underscores or starting with an underscore followed by a capital letter are *reserved* to the compiler/standard library. Declaring them or defining a macro with such a name causes undefined behavior in theory and in practice will cause problems if you happen to use an identifier that is actually used by the implementation. Use `MYHEADER_H_` or something similar, instead. – walnut Mar 02 '20 at 15:45
  • @walnut: excellent points. – El Stepherino Mar 03 '20 at 16:08