将一个extern模板放在头文件中,然后在单元编译文件中进行显式模板实例化有效吗?
例如,在g++
的编译示例中,这是否可以避免nothing<int>
两次的实例化?为什么没有人这样写,并且喜欢在每个.cpp文件中复制p 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;
}
答案 0 :(得分:3)
嗯,这肯定是有效的&#34;只要gcc能够编译它,并且完成你期望发生的事情。
至于为什么不是每个人都这样做,好吧,一旦你超越了这样的微不足道的情况,并开始管理大量广泛使用的模板,它将很快达到它的简单程度跟踪每个模板使用的每个参数变得不切实际,以便以这种方式显式地实例化它。
编译器可以更容易地为您跟踪它。
答案 1 :(得分:1)
如前所述,这是一个非常有效的用例,如果它适合您的编程模型,那么您应该使用它。但买家要小心:
有几个原因可以解释为什么extern模板通常不会在头文件中声明,然后在cpp文件中显式实例化。
实现模板类/函数的一个非常常见的模型是将定义放在头文件中,将实现放在“inl”或其他命名文件中。但是然后在头文件的底部包含该文件。有大量代码使用此方法来解决模板/标头/实现分离问题。将“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的实现。所以它可以编译得很好,但在链接时会有无法解析的符号。 所以他们试试这个:
template struct nothing<float>;
nothing<float> mynothing;
错误!现在编译器找不到实现,所有你得到的就是MORE错误。
现在你可以回到你的A.cpp文件并添加另一个浮动实例...你能说维护,头痛,腕管噩梦吗?使用常用的解决方案,你可以吃蛋糕然后吃。 (大部分)
现在你可能在想为什么甚至打扰extern?因为你的帖子暗示有一个典型的用例,大多数时候“无”将与int模板类型一起使用。在数百个文件中发生这种情况可能会导致严重的编译时间和代码大小分支。
标准委员会为什么不对这个烂摊子做些什么呢?他们做到了!他们添加了extern模板!平心而论,这是一个难以解决的问题。