我正在搞乱C ++ extern模板以加快编译速度。我注意到Visual Studio 2012在处理extern template
方面做了一些改进,但我仍然在发现问题。这是一个例子:
main.cpp中:
#include <iostream>
#include "Calc.h"
using namespace std;
int main(int argc, char** argv)
{
Calc<int> c1;
cout << c1.add(1, 2) << endl;
}
Calc.h:
#pragma once
template <class A_Type>
class Calc
{
public:
A_Type add(A_Type x, A_Type y)
{
return x + y;
}
};
extern template class Calc<int>;
通常我会将 Calc.cpp 包含在template class Calc<int>;
中,确保模板仅实例化一次。对于这个例子,我只是编译 Main.cpp 并期望它失败。
问题是,Visual Studio 2012将很乐意编译和链接上面的代码。它不尊重extern template
。我发现的唯一解决方案是在标题中执行此操作:
Calc.h:
#pragma once
template <class A_Type>
class Calc
{
public:
A_Type add(A_Type x, A_Type y);
};
template <class A_Type> A_Type Calc<A_Type>::add(A_Type x, A_Type y)
{
return x + y;
}
extern template class Calc<int>;
如果标题是这样的话,Visual Studio无法链接(抱怨Calc<int>::add
缺少定义,如预期的那样)。 然而, g ++ 4.6.3 无法链接其中任何一个示例。
谁是对的?如果一个类中的函数的原型和定义都在同一个头文件中指定,那真的有区别吗?有没有办法指定“简短形式” Calc.h 并让它在Visual Studio 2012(以及gcc)中按预期失败?
答案 0 :(得分:4)
如果编译器选择这样做,编译器可以自由内联它具有定义的任何函数。一旦内联,就不需要在另一个文件中使用另一个定义。
答案 1 :(得分:0)
根据第14.7.3节中的标准,
除内联函数和类模板特化外, 显式实例化声明具有抑制的效果 他们引用的实体的隐式实例化。
在您的第一个示例中,Calc<int>::add
是内联的。
[注意:意图是内联函数是主题 显式实例化声明仍然是隐式的 odr-used(3.2)时实例化,以便可以考虑身体 用于内联,但没有内联函数的外联副本 将在翻译单元中生成。 - 结束说明]
请记住,虽然成员函数是内联的,但编译器可以自由决定是否实际内联。