我可以将 `extern template` 放入头文件中吗?
Can I put `extern template` into a header file?
将外部模板放在头文件中,然后在单元编译文件中进行显式模板实例化是否有效?
例如在 g++
的编译示例中,这是否可以避免 nothing<int>
的实例化两次?为什么没有人这样写,而更喜欢在每个 .cpp 文件中复制 pase extern template
行?
A.hpp:
#ifndef HEADERC_A
#define HEADERC_A
template< typename T > struct nothing {};
extern template struct nothing<int>;
#endif
A.cpp:
#include "A.hpp"
template struct nothing<int>;
main.cpp:
#include "A.hpp"
#include <iostream>
int main()
{
nothing<int> n;
return 0;
}
好吧,这肯定是 "valid",因为 gcc 将编译它,并且几乎可以完成您期望发生的事情。
至于为什么不是每个人都这样做,好吧,一旦你超越了像这样的微不足道的情况,开始管理大量广泛使用的模板,它很快就会达到简单的地步跟踪每个模板使用的每个参数变得不切实际,以便可以通过这种方式显式实例化它。
编译器会更容易跟踪它,对你来说。
如前所述,这是一个完全有效的用例,如果它适合您的编程模型,那么您应该使用它。但买家注意:
外部模板通常不在头文件中声明然后在 cpp 文件中显式实例化的原因有多种。
实现模板 classes/functions 的一种非常常见的模型是将定义放在头文件中,将实现放在 "inl" 或其他命名文件中。但是然后将该文件包含在头文件的底部。有大量代码使用这种方法来解决 template/header/implementation 分离问题。将 "extern" 放在实现的顶部使代码更易于阅读和维护,尤其是当涉及多个 类 时。这是一个例子:
A.hpp
#pragma once
template< typename T > struct nothing {
void donothing(T input); // fastest func around
};
#include "A.inl"
A.inl
// does NOT include A.hpp
extern template struct nothing<int>; // save time and space
template<typename T> nothing<T>::donothing { return; }
Instance.h
#include "A.hpp"
template struct nothing<int>; // compiler generates code now
但这一切中有一个隐藏的警告...
如果按照您的建议实施,那么当另一个人出现并想要时会发生什么:
nothing<float> mynothing;
编译器会看到头文件,但不会找到 float 的实现。所以它可能编译得很好,但是在 link 的时候会有无法解析的符号。
所以他们尝试这样做:
template struct nothing<float>;
nothing<float> mynothing;
错了!现在编译器找不到实现,你得到的只是更多错误。
现在您可以返回 A.cpp 文件并为浮动添加另一个实例...您能说维护、头痛、腕管噩梦吗?使用常用的解决方案,您可以吃到蛋糕。 (大部分)
现在您可能在想为什么还要费心使用 extern?因为正如您的 post 所暗示的那样,有一个典型的用例,其中大部分时间 "nothing" 将与 int 模板类型一起使用。在可能的数百个文件中发生这种情况可能会导致严重的编译时间和代码大小后果。
为什么标准委员会不对这个烂摊子做点什么?他们做到了!他们添加了外部模板!平心而论,这是一个很难事后解决的问题。
将外部模板放在头文件中,然后在单元编译文件中进行显式模板实例化是否有效?
例如在 g++
的编译示例中,这是否可以避免 nothing<int>
的实例化两次?为什么没有人这样写,而更喜欢在每个 .cpp 文件中复制 pase extern template
行?
A.hpp:
#ifndef HEADERC_A
#define HEADERC_A
template< typename T > struct nothing {};
extern template struct nothing<int>;
#endif
A.cpp:
#include "A.hpp"
template struct nothing<int>;
main.cpp:
#include "A.hpp"
#include <iostream>
int main()
{
nothing<int> n;
return 0;
}
好吧,这肯定是 "valid",因为 gcc 将编译它,并且几乎可以完成您期望发生的事情。
至于为什么不是每个人都这样做,好吧,一旦你超越了像这样的微不足道的情况,开始管理大量广泛使用的模板,它很快就会达到简单的地步跟踪每个模板使用的每个参数变得不切实际,以便可以通过这种方式显式实例化它。
编译器会更容易跟踪它,对你来说。
如前所述,这是一个完全有效的用例,如果它适合您的编程模型,那么您应该使用它。但买家注意:
外部模板通常不在头文件中声明然后在 cpp 文件中显式实例化的原因有多种。
实现模板 classes/functions 的一种非常常见的模型是将定义放在头文件中,将实现放在 "inl" 或其他命名文件中。但是然后将该文件包含在头文件的底部。有大量代码使用这种方法来解决 template/header/implementation 分离问题。将 "extern" 放在实现的顶部使代码更易于阅读和维护,尤其是当涉及多个 类 时。这是一个例子:
A.hpp
#pragma once
template< typename T > struct nothing {
void donothing(T input); // fastest func around
};
#include "A.inl"
A.inl
// does NOT include A.hpp
extern template struct nothing<int>; // save time and space
template<typename T> nothing<T>::donothing { return; }
Instance.h
#include "A.hpp"
template struct nothing<int>; // compiler generates code now
但这一切中有一个隐藏的警告...
如果按照您的建议实施,那么当另一个人出现并想要时会发生什么:
nothing<float> mynothing;
编译器会看到头文件,但不会找到 float 的实现。所以它可能编译得很好,但是在 link 的时候会有无法解析的符号。 所以他们尝试这样做:
template struct nothing<float>;
nothing<float> mynothing;
错了!现在编译器找不到实现,你得到的只是更多错误。
现在您可以返回 A.cpp 文件并为浮动添加另一个实例...您能说维护、头痛、腕管噩梦吗?使用常用的解决方案,您可以吃到蛋糕。 (大部分)
现在您可能在想为什么还要费心使用 extern?因为正如您的 post 所暗示的那样,有一个典型的用例,其中大部分时间 "nothing" 将与 int 模板类型一起使用。在可能的数百个文件中发生这种情况可能会导致严重的编译时间和代码大小后果。
为什么标准委员会不对这个烂摊子做点什么?他们做到了!他们添加了外部模板!平心而论,这是一个很难事后解决的问题。