2013-06-19 63 views
5

我专门设计了一个模板,并在MSVC编译器和MinGW/GCC之间遇到了不同的beahviour。这里是头文件:模板专业化 - MSVC和GCC/MinGW之间的不同行为

// MyClass.h 
#ifndef MYCLASS_HEADER 
#define MYCLASS_HEADER 

template<typename T> 
class MyClass { 
public: 
    virtual void doSomething() { 
     // some code 
    } 
}; 

// specialization prototype here 

#endif 

现在,区别。为了避免多个定义,我只在头文件中专门设计了一个原型,实现在一个cpp文件中。专业化是问题。海湾合作委员会/ MinGW的编译器只接受这一个:

template<> void MyClass<int>::doSomething(); // GCC version 

而且MSVC只有这个:

extern template void MyClass<int>::doSomething(); // MSVC version 

在CPP文件的实现上是相同的:

// MyClass.cpp 
#include "MyClass.h" 

template<> void MyClass<int>::doSomething() { 
    // some code 
} 

与GCC原型的MSVC编译器抛出一个“无法解析的外部符号”错误,GCC与MSVC版本抛出“专业化......实例化后”。

目前,我有解决方法:

#ifdef _MSC_VER 
extern template 
#else 
template<> 
#endif 
void MyClass<int>::doSomething(); 

在头文件。它有效,但我不喜欢它。有没有办法避免编译器特定的开关?

+0

您使用的是什么版本的MSVC和GCC? – Gonmator

+0

MSVC 2010 SP1和GCC 4.7 – WoJo

回答

5

这些都是不一样的东西:。

template<> void MyClass<int>::doSomething(); // GCC version 

extern template void MyClass<int>::doSomething(); // MSVC version 

第一个声明明确专业化,第二个声明了一个明确的实例

与GCC原型的MSVC编译器抛出一个“无法解析的外部符号”的错误,与MSVC版本的GCC抛出“专业化......实例化后”。

GCC错误告诉你,在文件早期有一个隐含的实例化MyClass<int>::doSomething()比明确的特化的声明;这是你的代码中的一个错误。在使用隐式实例化之前,必须先声明显式专用化,否则隐式实例化将使用主要模板定义,而不是专用化。通常可以通过在主模板的定义之后直接声明特化,以确保特化在使用之前进行声明,然后在MyClass<int>的任何实例化之前进行声明。

我不知道你为什么得到MSVC错误,这听起来好像你没有链接到MyClass.cpp。如果这不是它,你可以尝试添加一个显式实例定义MyClass.cpp迫使符号在该文件中发出:

template void MyClass<int>::doSomething(); // N.B. no "extern" on definition 

您是否尝试过声明专业化和实例,但要确保它们声明之前任何隐式实例?这应该是有效的C++,例如

#ifndef MYCLASS_H 
#define MYCLASS_H 
template<typename T> 
class MyClass { 
public: 
    virtual void doSomething() { 
     // some code 
    } 
}; 
// declare explicit specialization 
template<> void MyClass<int>::doSomething(); 
// declare explicit instantiation 
extern template void MyClass<int>::doSomething(); 
#endif 

// MyClass.cpp 
#include "MyClass.h" 

// define explicit specialization 
template<> void MyClass<int>::doSomething() { 
    // some code 
} 
// define explicit instantiation 
template void MyClass<int>::doSomething(); 

或者,如果你不能使这项工作有两种编译器,你可以把专用成员函数的定义页眉和声明它inline,这也将避免多个定义错误。

+0

'inline'解决了这个问题。现在,我在头文件中定义了:'template <> inline MyClass :: doSomething(){/ * code * /}'适用于两种编译器。谢谢 – WoJo

0

它看起来像标准说的extern是正确的,可能是一些实现了一个错误:

摘自14.7.2显式实例:

“为显式实例的语法是:
的extern选择模板声明

有两种形式显式实例化:显式实例化定义和显式实例化声明。一个显式实例声明始于extern关键字“

+0

标准还规定“_An明确的特殊化以下任何一个类模板的成员函数[...]可以通过'template <>引入的声明来声明' _”。尽管知道什么编译器工作正常,但是这并不能回答这个问题。 – Gonmator

+0

然后我想我的答案是否定的,在编译器符合性增加之前,你可能是以最好的方式做到这一点。 – TractorPulledPork

+0

'extern'是正确的**如果你想声明一个明确的实例** ......不清楚这是OP想要做什么,尽管 –