模板特化 - MSVC和GCC/MinGW之间的不同行为

WoJ*_*oJo 5 c++ gcc templates mingw visual-c++

我专门设计了一个模板,在MSVC编译器和MinGW/GCC之间遇到了不同的问题.这是头文件:

// MyClass.h
#ifndef MYCLASS_HEADER
#define MYCLASS_HEADER

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

// specialization prototype here

#endif
Run Code Online (Sandbox Code Playgroud)

现在,差异.为了避免多个定义,我只在头文件中专门设计原型,实现在cpp文件中.专业化是问题所在.GCC/MinGW编译器只接受这一个:

template<> void MyClass<int>::doSomething(); // GCC version
Run Code Online (Sandbox Code Playgroud)

而MSVC只有这个:

extern template void MyClass<int>::doSomething(); // MSVC version
Run Code Online (Sandbox Code Playgroud)

CPP文件中的实现对于两者都是相同的:

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

template<> void MyClass<int>::doSomething() {
   // some code
}
Run Code Online (Sandbox Code Playgroud)

使用GCC原型,MSVC编译器抛出"未解析的外部符号"错误,GCC与MSVC版本抛出"实例化后......的专业化".

目前,我有解决方法:

#ifdef _MSC_VER
extern template
#else
template<>
#endif
void MyClass<int>::doSomething();
Run Code Online (Sandbox Code Playgroud)

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

Jon*_*ely 5

这些不是一回事:

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

extern template void MyClass<int>::doSomething(); // MSVC version
Run Code Online (Sandbox Code Playgroud)

第一个声明的明确分工,第二个声明了一个明确的实例.

使用GCC原型,MSVC编译器抛出"未解析的外部符号"错误,GCC与MSVC版本抛出"实例化后......的专业化".

GCC错误告诉您MyClass<int>::doSomething()文件中早先存在隐式实例化,而不是显式特化的声明; 这是代码中的错误.您必须在使用它之前声明显式特化,这会导致隐式实例化,否则隐式实例化将使用主模板定义,而不是特化.在任何实例化之前,通常可以确保在使用之前声明特化,方法是在主模板定义之后直接声明特化MyClass<int>.

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

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

您是否尝试宣告 双方的专业化和实例,但确保他们宣布之前任何隐含的实例?这应该是有效的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
Run Code Online (Sandbox Code Playgroud)

.

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

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

或者,如果您无法使用两个编译器,则可以将专用成员函数的定义放在标头中并声明它inline,这也可以避免多个定义错误.