5

我专门设计了一个模板,但在 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

现在,区别。为了避免多重定义,我只在头文件中专门设计了一个原型,实现在一个 cpp 文件中。专业是问题。GCC/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 编译器会抛出“无法解析的外部符号”错误,使用 MSVC 版本的 GCC 会抛出“实例化后……的特殊化”。

目前,我有解决方法:

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

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

4

2 回答 2

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,这也可以避免多个定义错误。

于 2013-06-19T15:48:46.553 回答
0

看起来标准说 extern 是正确的,可能是某些实现中的错误:

摘自 14.7.2 显式实例化:

"显式实例化的语法是:
extern opt 模板 声明

显式实例化有两种形式:显式实例化定义和显式实例化声明。显式实例化声明以 extern 关键字开头。”

于 2013-06-19T15:43:12.273 回答