类模板与接口和实现分开的文件

huangapple go评论62阅读模式
英文:

Class template with interface and implementation in separate files

问题

I have some template classes that are separated into header files and implementation files:

// MyTemplate.h
template<class T>
class MyTemplate {
public:
    void Foo();
};
// MyTemplate.cpp
#include "MyTemplate.h"
template<class T>
void MyTemplate<T>::Foo() {
    // ...
}

To use MyTemplate in another translation unit I can #include the implementation file:

#include "MyTemplate.cpp"
template class MyTemplate<int>;

This way I get to:

  1. Keep the interface and implementation in separate files.
  2. Not have to maintain a list of all template instantiations in the implementation file.

I am in the process of converting to C++ modules. Is there any way to achieve the same with modules, when I should no longer use #include?

英文:

I have some template classes that are separated into header files and implementation files:

// MyTemplate.h
template&lt;class T&gt;
class MyTemplate {
public:
    void Foo();
};
// MyTemplate.cpp
#include &quot;MyTemplate.h&quot;
template&lt;class T&gt;
void MyTemplate&lt;T&gt;::Foo() {
    // ...
}

To use MyTemplate in another translation unit I can #include the implementation file:

#include &quot;MyTemplate.cpp&quot;
template class MyTemplate&lt;int&gt;;

This way I get to:

  1. Keep the interface and implementation in separate files.
  2. Not have to maintain a list of all template instantiations in the implementation file.

I am in the process of converting to C++ modules. Is there any way to achieve the same with modules, when I should no longer use #include?

答案1

得分: 2

在模块中,这可以通过简单地创建一个接口分区来轻松完成。这必须是一个 接口 分区,因为模板定义仍然是你的接口的一部分,所以它必须对导入它的人可见(就像常规的C++一样)。

这是如何完成的:

//主接口模块
export module MyTemplates;

export import :TemplateDef;
//您模块的其他内容。
//模板的定义
export module MyTemplates:TemplateDef;

import :TemplateDecl;

template<class T>
export void MyTemplate<T>::Foo() {
    // ...
}
//模板的声明
export module MyTemplates:TemplateDecl;

template<class T>
export class MyTemplate {
public:
    void Foo();
};

话虽如此,因为定义必须对所有人都可用,将它们分为两个文件几乎没有什么好处。如果更改定义文件,导入模块的所有人仍然必须重新编译。这就是模板的工作方式。


请注意,你的代码的非模块形式相当糟糕。将模板实现与接口分开是可以的;但使用名为 ".cpp" 的文件是不可以的。头文件是用来包含的;这就是为什么我们称它们为 "头文件" 的原因。当用户看到一个扩展名为 ".cpp" 的文件时,他们会假设它 应该被包含。

只需在两者都使用 ".h" 扩展名。 ".hxx" 也经常用于实现(应该由 ".h" 版本包含)。

英文:

In modules, this is trivially done by simply creating a interface partition. This has to be an interface partition because the template definition is still part of your interface, so it has to be visible to those importing it (just like regular C++).

This is done as follows:

//Primary interface module
export module MyTemplates;

export import :TemplateDef;
//Other stuff for your module.
//Definition for your template.
export module MyTemplates:TemplateDef;

import :TemplateDecl;

template&lt;class T&gt;
export void MyTemplate&lt;T&gt;::Foo() {
    // ...
}
//Declaration for your template
export module MyTemplates:TemplateDecl;

template&lt;class T&gt;
export class MyTemplate {
public:
    void Foo();
};

That being said, because definitions have to be made available to everyone, there's little to be gained by separating these into two files. If you change the definition file, everyone importing your module still has to be recompiled. That's just how templates work.


Note that the non-modular form of your code is pretty bad. Separating template implementation from interface is fine; doing it with a file named ".cpp" is not. Headers are meant to be included; that's why we call them "headers". The assumption a user will make upon seeing a file with the ".cpp" extension is that it is not supposed to be included.

Just use the ".h" extension with both. ".hxx" is also often used for the implementation (which should be included by the ".h" version).

huangapple
  • 本文由 发表于 2023年4月19日 22:04:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/76055475.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定