4

I don't want to write a .cpp file for every simple c++ class.

when I write a class definition and declaration in a single .hpp file, the linker complains about multiple definition of member functions which are not implemented inside the body of the class.

So I use templates to get rid of linker complaints:

// log.hpp file
template<typename T>
class log_t {
private:
    int m_cnt = 0;
public:
    void log();
};

template<typename T>
void log_t<T>::log() {
    std::cout << ++m_cnt << std::endl;
}

// some random type (int)
typedef log_t<int> log;

And then I can simply use log class in multiple .cpp files without linker complaints.

Is there something fundamentally wrong with this method?

Edit: even when i use this method will member functions become inline ?

amin
  • 3,672
  • 5
  • 33
  • 61
  • 10
    Use templates when you need templates, not just to fix linker errors – Jonathan Wakely Mar 18 '14 at 12:20
  • 3
    You're using a hammer to screw in a screw – Salgar Mar 18 '14 at 12:21
  • 1
    _I don't want to write a .cpp file for every simple c++ class._: don't. Write a .cpp file for every .h (or .hpp) file instead. If the class is large enough to have its own header, give it its own implementation. If it's small enough to group with others, do the same for their implementations. – mah Mar 18 '14 at 12:34
  • 1
    Adding a [header guard](https://www.learncpp.com/cpp-tutorial/header-guards/) may help in similar situations. – jvriesem May 11 '20 at 15:50

3 Answers3

6

If some class doesn't need to be a template, don't make it a template just to "get rid of the linker's complains". Just use proper coding techniques, like providing inline defintions of member functions:

// log.hpp file

#pragma once

#include <iostream> // For std::cout, std::endl

class log {
private:
    static int m_cnt = 0;
public:
    log();
};

// Note "inline" here:
inline log::log() {
    std::cout << ++m_cnt << std::endl;
}

If you provide the function's body inside the class definition, then there's no need to specify the keyword inline:

// log.hpp file

#pragma once

#include <iostream> // For std::cout, std::endl

class log {
private:
    static int m_cnt = 0;
public:
    // Function body inserted here (no need for "inline"):
    log() {
        std::cout << ++m_cnt << std::endl;        
    }
};
Mr.C64
  • 41,637
  • 14
  • 86
  • 162
3

As you want the functions to be defined in headers (which are included in multiple source files, which leads to multiple definitions in your case), you should make the functions inline.

2 options:

  • implicit inline - do not separate the function definitions
  • explicit inline - manually add inline keyword in front of the definitions

Using templates just to "work-around" this error is not a good idea. Use templates only when you need them.

Kiril Kirov
  • 37,467
  • 22
  • 115
  • 187
1

What's wrong with this Method ? Is there something fundamentally wrong with this method ?

No, nothing is wrong with this method. What you need to do is to comply with One Definition Rule by doing:

  1. Make function definition inline by either putting the definition inside the declaration or by putting inline keyword before every function declaration. This is to avoid multiple definitions in multiple translation units (cpp files to simplify a little)
  2. Put include guards in the header files. This is to avoid multiple inclusion in the same translation unit.

Actually, this method is the only method for a template to work. You can't put the template definition in a cpp file, and expect it to work, because C++ compiler would need the definition to instantiate the template. Using template is not a solution for this method to work, but a mandate that requires you to only use this method if you want your code to compile.

Community
  • 1
  • 1
WiSaGaN
  • 46,887
  • 10
  • 54
  • 88