当使用c++模块时,有任何理由将函数声明(.hpp文件)与其定义(.cpp文件)分开

When using C++ modules, is the any reason to separate function declarations (.hpp files) from their definitions (.cpp files)?

本文关键字:文件 声明 hpp 分开 cpp 定义 函数 模块 c++ 理由 任何      更新时间:2023-10-16

我习惯编写没有模块的代码,其中头文件包含函数声明,如:

// foo.h 
class Foo
{
    void bar();
};

和相应的.cpp文件包含如下定义:

// foo.cpp
#include "foo.h"
void Foo::bar()
{
    // ...
}

据我所知,这样做是为了减少编译时间和减少依赖。当使用模块时,这仍然适用吗?如果像Java和c#那样将类的定义放在一个文件中,速度会一样快吗?如果是这种情况,在使用模块时是否需要同时使用.hpp.cpp文件?

我所知道的唯一原因,正如模块提案目前所处的位置,是处理循环接口依赖关系。

如果一个程序由模块组成,并且它没有将函数声明与定义分开,那么所有模块文件都将是模块接口(与模块实现相反)。如果你想将它们与头文件和代码文件进行比较,模块接口可以被视为头文件(.hpp),模块实现可以被视为代码文件(.cpp)。

不幸的是,模块建议不允许循环模块接口依赖。并且由于您的程序现在完全由模块接口组成,因此您将永远无法以任何方式拥有两个相互依赖的模块(这可能会在将来通过proclaimed ownership声明得到改进,但目前不支持)。解决循环模块接口依赖的唯一方法是分离声明和定义,并将循环导入放在模块实现文件中,与循环模块接口依赖相反,循环模块实现依赖是允许的。

下面的代码提供了一个不分离声明和定义就无法编译的情况示例:

Foo module file

export module Foo;
import module Bar;
export namespace Test {
    class Foo {
    public:
        Bar createBar() {
            return Bar();
        }
    };
}

Bar module file

export module Bar;
import module Foo;
export namespace Test {
    class Bar {
    public:
        Foo createFoo() {
            return Foo();
        }
    };
}

本文展示了一个示例,说明如果proclaimed ownership声明可用,如何解决这个问题。从本质上讲,它可以归结为分离声明和定义。

在一个完美的世界中,编译器将能够处理这种情况,但是,唉,据我所知,当前建议的模块实现不支持它。

仍然有很多理由使用头文件。

在不看到底层细节的情况下,共享和理解对象api的便利性足以让它们留在身边。这是一个20英尺的物体,基本上是一个轮廓。

如果你出售一个库,你应该包括一个头文件,以及存档文件或共享库。通过这种方式,您可以在不损害产品IP的情况下保持信息的专有性,并且您的客户可以包含为其目标编译的二进制文件。

我不相信没有头文件这是不可能的

这里有一个很好的讨论,解释了模块的思想。

简而言之,你是对的,头文件和实现文件之间的分离将不再需要。#include指令将被import指令取代,并且在编译时模块将提供所需的信息,否则这些信息将包含在包含的头文件中。

这个习语的另一个用法继承自C语言;即使对于不依赖于其他翻译单元的翻译单元,它也是一种方便的前向声明方式。

使用预编译头文件并没有真正成为一件重要的事情,直到c++扩展了头文件的使用,为了性能的原因才成为必要(尽管有一些非常大的老式头文件,如windows.h)。

这个想法似乎是引入一些更像c#/Java机制的东西。c++的机制在精神上是非常模块化/ADA的。如果机器能为我们做更多的工作就好了。