简体   繁体   中英

c++ classes without .cpp file without inline functions?

I already asked a similar question but this one is a bit different

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 or defined with inline keyboard.

For example this will work but member functions will become inline :

// log.hpp file
#pragma once
#include<iostream>

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

inline void log::log() {
    std::cout << ++m_cnt << std::endl;
}

So I use templates to get rid of linker complaints and hope that member functions will not become inline(do they ?):

// log.hpp file
#pragma once
#include<iostream>

template<typename T>
class log_t {
  private:
    static 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.

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

In general, having every implementation in header files is a BAD idea, since it can lead to very long compile times for larger projects. Using templates to avoid this is not really a good idea, either, since it does not change this fact.

inline is only a hint to the compiler; it may ignore it and inline your template code or not. In short: The answer to your question does not matter. The standard/best way would be to use .cpp files for the implementation, even if you want to avoid it.

While it is in general bad practice to put everything in a single .h file, there are situations where it's more convenient to do so. Especially when defining small classes, and during prototyping phase where the code can change a lot quickly.

I really don't recommend using templates to solve the linking issue, since it's can slow down compilation and leads to confusion: it's like creating a function taking an argument when you except that argument to always have the same value. Anyway, typing inline is shorter than template<typename T> ;)

So you either have to define your methods in the class body or annotate them with inline if defined out of the body. This is equivalent, since C++ automatically adds inline to methods defined in the class body.

Your concern appears to be with the generated code, you probably wonder if the binary is going to grow too much. But everything's cool since regardless of inline annotations, the compiler looks at every function call and decides whether to inline it or generate a call. This means the same function may sometimes be inlined (if called in a loop) and sometimes be called.

Different compilers have different heuristics, but the inline keyword doesn't have a particularly strong influence on the compiler's decision. You can use things like __forceinline or __attribute__((always_inline)) to make ask more strongly to inline a function, but even then there's no guarantee all calls to the function will be inlined. On the contrary, you may be interested in __attribute__(noinline) for gcc which will (nearly) never inline the call:

inline __attribute__(noinline) void log::log() // gcc
{
    std::cout << ++m_cnt << std::endl;
}

If you want to really know what's happening in your code you can use -Winline to see when inline functions are not inlined.

You can also use -Os or -Oz optimization levels to change internal compiler thresholds, so that it will do less inlining.

Related questions which may interest you : here and here .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM