没有内联函数的没有.cpp文件的c ++类?

ami*_*min 3 c++ linker templates c++11

我已经问了一个类似的问题,但这个问题有点不同

我不想为每个简单的c ++类编写.cpp文件.

当我在单个.hpp文件中编写类定义和声明时,链接器会抱怨成员函数的多个定义,这些函数没有在类的主体内部实现或者使用内联键盘定义.

例如,这将起作用,但成员函数将变为内联:

// 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;
}
Run Code Online (Sandbox Code Playgroud)

所以我使用模板来摆脱链接器投诉,并希望成员函数不会内联(是吗?):

// 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;
Run Code Online (Sandbox Code Playgroud)

然后我可以简单地在多个.cpp文件中使用日志类而不需要链接器投诉.

即使我使用这种方法会将成员函数变成内联吗?

and*_*ras 5

通常,在头文件中进行每个实现都是一个坏主意,因为它可能导致较大项目的编译时间非常长.使用模板来避免这种情况也不是一个好主意,因为它不会改变这一事实.

inline只是对编译器的暗示; 它可能会忽略它并内联您的模板代码.简而言之:你的问题的答案无关紧要.标准/最佳方法是使用.cpp文件进行实现,即使您想避免它.

  • 阿明,这是可能的.但是`inline`只是对编译器的一个暗示.它可能内联您没有声明为"inline"的内容,或者生成一个单独的函数,尽管某些内容被声明为"inline". (3认同)
  • Jefffrey,他们正在模仿他们的东西,所以没有其他选择;-)(嗯,有,但它涉及将头分成接口和实现头,并实例化.cpp文件中每个常用的模板参数组合...) (2认同)

Ant*_*ine 5

虽然将所有内容放在一个.h文件中通常是不好的做法,但有些情况下这样做会更方便.特别是在定义小类时,以及在原型设计阶段,代码可以快速改变很多.

我真的不建议使用模板来解决链接问题,因为它可能会减慢编译速度并导致混淆:就像创建一个函数接受参数时,除了该参数总是具有相同的值.无论如何,打字inline是短于template<typename T>)

因此,您必须在类主体中定义方法,或者inline在主体外定义时使用它们进行注释.这是等效的,因为C++会自动添加inline到类体中定义的方法.

您的担心似乎与生成的代码有关,您可能想知道二进制文件是否会增长太多.但是一切都很酷,因为无论inline注释如何,编译器都会查看每个函数调用并决定是内联还是生成调用.这意味着有时可以内联相同的函数(如果在循环中调用),有时也可以调用.

不同的编译器具有不同的启发式,但inline关键字对编译器的决策没有特别强烈的影响.你可以使用类似__forceinline__attribute__((always_inline))更强烈的内容来内联函数,但即使这样,也不能保证所有对函数的调用都会被内联.相反,你可能__attribute__(noinline)对gcc感兴趣,它将(几乎)永远不会内联电话:

inline __attribute__(noinline) void log::log() // gcc
{
    std::cout << ++m_cnt << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

如果您想真正了解代码中发生的情况,可以使用它-Winline来查看inline函数何时没有内联.

您还可以使用-Os-Oz优化级别来更改内部编译器阈值,以便它可以减少内联.

您可能感兴趣的相关问题:此处此处.