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

时间:2016-09-23 17:42:08

标签: c++ c++20 c++-modules

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

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

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

// foo.cpp
#include "foo.h"

void Foo::bar()
{
    // ...
}

据我所知,这是decrease compile time and reduce dependencies完成的。如果使用modules,这仍然适用吗?将类放在单个文件中的定义与Java和C#的定义方式一样快吗?如果是这种情况,使用模块时是否需要.hpp.cpp个文件?

4 个答案:

答案 0 :(得分:3)

我知道的唯一原因as the modules proposal currently stands是处理循环接口依赖项。

如果程序由模块组成,并且没有将函数声明与定义分开,则所有模块文件均为模块接口(与模块实现相对)。如果要将它们与头文件和代码文件进行比较,则模块接口可以看作是头文件(.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();
        }
    };
}

This article显示了一个示例,说明如何使用proclaimed ownership声明来解决此问题。从本质上讲,它可以归结为声明和定义的分离。

在理想情况下,编译器将能够处理这种情况,但是据我所知,目前建议的模块实现不支持这种情况。

答案 1 :(得分:2)

使用头文件仍有很多原因。

在不查看底层细节的情况下,轻松共享和理解对象api足以保持它们的存在。它是一个很好的20英尺的物体视图,基本上是一个轮廓。

如果您要销售库,则应包含头文件,存档文件或共享库。这样,您可以在不影响产品IP的情况下保持信息专有,并且您的客户可以包含为其目标编译的二进制文件。

如果没有头文件,我不相信这是可能的。

答案 2 :(得分:1)

有一个很好的讨论here解释了模块的概念。

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

答案 3 :(得分:1)

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

预编译头文件的使用并没有真正成为一件重要的事情,直到C ++扩展使用头文件使其成为必要的性能原因(尽管有一些非常大的旧学校标题,如windows.h )。

这个想法似乎确实带来了更像C#/ Java机制的东西。 C ++机制本质上是Modula / ADA。让机器为我们做更多的工作会很好。