msvc 11仅在某些情况下尊重C ++ extern模板

时间:2012-09-11 02:44:10

标签: c++ templates visual-c++ c++11

我正在搞乱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)中按预期失败?

2 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分:0)

根据第14.7.3节中的标准,

  

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

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

  

[注意:意图是内联函数是主题   显式实例化声明仍然是隐式的   odr-used(3.2)时实例化,以便可以考虑身体   用于内联,但没有内联函数的外联副本   将在翻译单元中生成。 - 结束说明]

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