c++ - 同一翻译单元中的模板类和各自的外部模板类

标签 c++ templates c++11 extern

这是 C++11 中 extern 模板的正确用法吗? (难道 extern template class 和相应的 template class 在同一个翻译单元中可见吗?)

// example.hpp:
#pragma once
template< typename T >
class C {
    void f(T);
};
// question is about the next two lines
extern template class C< float >;
extern template class C< double >;
// example_def.hpp:
#include "example.hpp"
template< typename T >
void C< T >::f(T) {
    //... smth. practicable
}
// example.cpp:
#include "example_def.hpp"
template class C< float >;
template class C< double >;
// other.hpp:
#pragma once
void g();
// other.cpp:
#include "other.hpp"
#include "example.hpp"
// maybe those two lines should be here instead?
void g() {
    C< float >();
    C< double >();
}
// main.cpp:
#include "example.hpp"
#include "other.hpp"
// ...and here?
int main() {
    C< float >();
    C< double >();
    g();
    return 0;
}

最佳答案

是的,外部模板类规范(标准称为显式实例化声明)和模板类 规范(被标准称为显式实例化定义)可以在同一个翻译单元中,如果定义(没有extern)遵循声明(使用 extern):

(§14.7.2/11) If an entity is the subject of both an explicit instantiation declaration and an explicit instantiation definition in the same translation unit, the definition shall follow the declaration. An entity that is the subject of an explicit instantiation declaration and that is also used in a way that would otherwise cause an implicit instantiation (14.7.1) in the translation unit shall be the subject of an explicit instantiation definition somewhere in the program; otherwise the program is ill-formed, no diagnostic required. [ Note: This rule does apply to inline functions even though an explicit instantiation declaration of such an entity has no other normative effect. This is needed to ensure that if the address of an inline function is taken in a translation unit in which the implementation chose to suppress the out-of-line body, another translation unit will supply the body. — end note ] An explicit instantiation declaration shall not name a specialization of a template with internal linkage.

(强调我的)。术语显式实例化声明显式实例化定义 定义如下:

(§14.7.2/2) The syntax for explicit instantiation is:

explicit-instantiation:
externopt template declaration

There are two forms of explicit instantiation: an explicit instantiation definition and an explicit instantiation declaration. An explicit instantiation declaration begins with the extern keyword.


这些显式实例化的效果如下:

  1. 显式实例化声明(使用 extern)阻止所有隐式实例化生效(除了内联函数和类模板特化,§14.7.2/10)。

  2. 显式实例化定义(没有extern)导致实例化发生无论如何,即它覆盖显式实例化声明(这也遵循§ 14.7.2/10).


一般评论
您的显式实例化声明位于定义模板的头文件中这一事实意味着任何人包含头文件以使用模板的人都必须同时添加一个显式实例化< em>定义,或者需要链接到另一个包含此类显式实例化定义的 .cpp 文件的代码。

当您期望许多不同的用户为许多不同类型实例化模板时,这可能会造成混淆并且可能不是一个好主意。但是,如果不同类型的实例化数量很少并且您可以预料到它们,那么这可能是明智的。当然,您必须确保有一个(或多个).cpp 文件包含所有所需实例化的显式实例化定义,并且其对应的对象文件在构建时与项目链接。

关于c++ - 同一翻译单元中的模板类和各自的外部模板类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14021243/

相关文章:

C++ 逐个读取大文件

c++ - Lemon Parser 会跳过一些东西(或者我的误解)

c++ - solaris 上支持 C++11/14 的 GNU gcc/g++ 编译器版本

c++ - C++/CX 中的 [this] 是什么? (Windows 8)

c++ - 左值引用和右值引用的区别

c++ - 为什么使用 std::forward 禁用模板参数推导?

c++ - 在 C++14 中不指定对象的左值

c++ - 模型中虚拟索引实现的替代方案

c++ - 返回类型重载函数? (重访)

c++ - 从表中检索混合数据类型的模板化 get 方法