【问题标题】:Template specialization - different behaviour between MSVC and GCC/MinGW模板专业化 - MSVC 和 GCC/MinGW 之间的不同行为
【发布时间】:2013-06-19 15:21:30
【问题描述】:

我专门化了一个模板,并在 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();

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

【问题讨论】:

  • 您使用的是什么版本的 MSVC 和 GCC?
  • MSVC 2010 SP1 和 GCC 4.7

标签: c++ templates visual-c++ gcc mingw


【解决方案1】:

这些不是一回事:

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

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

第一个声明显式专业化,第二个声明显式实例化

使用 GCC 原型时,MSVC 编译器会抛出“无法解析的外部符号”错误,使用 MSVC 版本的 GCC 会抛出“实例化后 ... 的特殊化”。

GCC 错误告诉您在文件中比显式特化声明更早的 MyClass&lt;int&gt;::doSomething() 的隐式实例化;这是您的代码中的一个错误。您必须在使用它导致隐式实例化之前声明显式特化,否则隐式实例化将使用主模板定义,而不是特化。您通常可以通过在主模板定义之后、MyClass&lt;int&gt; 的任何实例化之前直接声明特化来确保在使用之前声明特化。

我不知道您为什么会收到 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,这也可以避免多个定义错误。

【讨论】:

  • inline 解决了这个问题。现在,我在头文件中有定义:template&lt;&gt; inline MyClass&lt;int&gt;::doSomething() { /*code*/ } 适用于两种编译器。谢谢
【解决方案2】:

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

摘自 14.7.2 显式实例化:

"显式实例化的语法是:
externopttemplate declaration

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

【讨论】:

  • 标准还说“可以通过@987654321引入的声明来声明类模板[...]的以下任何[...]成员函数的显式特化@”。尽管知道什么编译器可以正常工作非常有趣,但这并不能回答问题。
  • 那么我想我的答案是否定的,在编译器一致性提高之前,您可能正在这样做。
  • extern 是正确的如果你想声明一个明确的实例化 ...目前尚不清楚这就是 OP 想要做的事情
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-08
  • 2021-03-09
  • 2011-12-22
  • 1970-01-01
相关资源
最近更新 更多