2

以下代码不会生成编译/链接器错误/警告:

// A.h
#include<iostream>
struct A
{
  template<typename T>
  static void foo (T t)
  {
    std::cout << "A::foo(T)\n";
  }
};
void other ();

// main.cpp
#include"A.h"
int main ()
{
  A::foo(4.7);
  other();
}

// other.cpp
#include"A.h"
template<>
void A::foo (double d)
{
  cout << "A::foo(double)\n";
}

int other ()
{
  A::foo(4.7);
}

令人惊讶的输出是:

A::foo(T)
A::foo(double)

A::foo(double)为什么编译器在 的情况下无法选择正确的main.cpp

同意,如果有A.h如下声明,则没有预期的问题:

template<> void A::foo (double);

但这不是问题,因为在链接时,编译器有专门的版本。

此外,是否具有相同功能的 2 个不同版本的未定义行为

4

3 回答 3

6

所有显式特化声明必须在模板实例化时可见。由于您的显式特化声明A::foo<double>在一个翻译单元中可见,但在另一个翻译单元中不可见,因此该程序格式错误。

(实际上,编译器将在 中实例化主模板,在 中实例化main.cpp显式专用模板other.cpp。无论如何,这仍然会违反 ODR。)

于 2012-10-26T14:25:39.753 回答
0

main.cpp看不到里面的代码other.cpp。模板特化属于文件范围。

于 2012-10-26T14:26:58.433 回答
0

为什么编译器无法在 main.cpp 的情况下选择正确的 A::foo(double) ?

问题在于,在一个单独的编译模型中,在标头中没有可用的声明,编译器可能不知道任何翻译单元中是否存在稍后将链接的特化,或者它是否需要实例化模板。语言中的决定是没有声明意味着没有手动专门化模板,因此编译器现在需要生成一个。

是否有相同功能的 2 个不同版本是未定义的行为?

是的。无论是否自动生成其中一种特化,事实是它是未定义的行为,因为它违反了单一定义规则(同一符号有多个定义)。

于 2012-10-26T15:17:59.737 回答