我可以将“extern template”放入头文件中吗?

Lær*_*rne 5 c++ templates c++11

将外部模板放入头文件中,然后在单元编译文件中进行显式模板实例化是否有效?

例如,在编译示例中g++,这是否可以避免nothing<int>两次实例化?为什么没有人这样写,而更喜欢extern template在每个 .cpp 文件中复制该行?

A.hpp:

#ifndef HEADERC_A
#define HEADERC_A

template< typename T > struct nothing {};
extern template struct nothing<int>;

#endif
Run Code Online (Sandbox Code Playgroud)

A.cpp:

#include "A.hpp"

template struct nothing<int>;
Run Code Online (Sandbox Code Playgroud)

主要.cpp:

#include "A.hpp"
#include <iostream>

int main()
{
    nothing<int> n;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

小智 1

如前所述,这是一个完全有效的用例,如果它适合您的编程模型,那么您应该使用它。但买家要注意:

为什么 extern 模板通常不在头文件中声明,然后在 cpp 文件中显式实例化,有几个原因。

实现模板类/函数的一个非常常见的模型是将定义放在头文件中,并将实现放在“inl”或其他命名文件中。但随后将该文件包含在头文件的底部。有大量代码使用这种方法来解决模板/标头/实现分离问题。将“extern”放在实现的顶部可以使代码更易于阅读和维护,特别是当涉及多个类时。这是一个例子:

黄曲霉

#pragma once
template< typename T > struct nothing {
  void donothing(T input); // fastest func around
};
#include "A.inl"
Run Code Online (Sandbox Code Playgroud)

A.inl

// does NOT include A.hpp
extern template struct nothing<int>; // save time and space
template<typename T> nothing<T>::donothing { return; }
Run Code Online (Sandbox Code Playgroud)

实例.h

#include "A.hpp"
template struct nothing<int>; // compiler generates code now
Run Code Online (Sandbox Code Playgroud)

但这一切都有一个隐藏的警告......

如果这按照您的建议实施,那么当另一个人出现并想要时会发生什么:

nothing<float> mynothing;
Run Code Online (Sandbox Code Playgroud)

编译器会看到头文件,但永远找不到 float 的实现。所以它可能编译得很好,但在链接时会出现无法解析的符号。所以他们尝试这样做:

template struct nothing<float>;
nothing<float> mynothing;
Run Code Online (Sandbox Code Playgroud)

错误的!现在编译器找不到实现,你得到的只是更多错误。

现在您可以返回 A.cpp 文件并添加另一个浮动实例...您可以说维护、头痛、腕管噩梦吗?使用常用的解决方案,您可以鱼与熊掌兼得。(大多)

现在您可能会想为什么还要麻烦外部人员呢?因为正如您的帖子所暗示的那样,有一个典型的用例,大多数情况下“无”将与 int 模板类型一起使用。在可能的数百个文件中发生这种情况可能会导致严重的编译时间和代码大小影响。

为什么标准委员会不采取行动来解决这个混乱局面?他们做到了!他们添加了外部模板!平心而论,这是一个事后很难解决的问题。