1

我正在使用 C++ 外部模板来加快编译速度。我注意到 Visual Studio 2012 在处理extern template. 这是一个例子:

主.cpp:

#include <iostream>
#include "Calc.h"

using namespace std;

int main(int argc, char** argv)
{
    Calc<int> c1;
    cout << c1.add(1, 2) << endl;
}

计算.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.cpptemplate class Calc<int>;确保模板只实例化一次。对于这个例子,我只编译Main.cpp并期望它失败。

问题是,Visual Studio 2012 会愉快地编译和链接上面的代码。它不尊重extern template. 我发现的唯一解决方案是在标题中执行此操作:

计算.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)中按预期失败?

4

2 回答 2

4

编译器可以自由地内联它定义的任何函数,如果它选择这样做的话。一旦它被内联,就不需要在另一个文件中进行另一个定义。

于 2012-09-11T02:56:57.887 回答
0

根据第 14.7.3 节中的标准,

除了内联函数和类模板特化,显式实例化声明具有抑制它们所引用实体的隐式实例化的效果。

在您的第一个示例Calc<int>::add中是内联的。

[注意:意图是作为显式实例化声明主题的内联函数在使用odr(3.2)时仍将被隐式实例化,以便可以考虑将主体内联,但没有外联副本的内联函数将在翻译单元中生成。——尾注]

请记住,尽管成员函数是内联的,但编译器可以自由决定它是否实际上是内联的。

于 2016-04-19T09:30:25.893 回答