为什么没有声明从.cpp文件中获取模板函数的完全特化?

时间:2012-10-26 14:22:42

标签: c++ templates template-specialization language-lawyer

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

// 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);

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

此外,有两个不同版本的相同功能未定义的行为

3 个答案:

答案 0 :(得分:6)

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

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

答案 1 :(得分:0)

main.cpp无法查看other.cpp内的代码。模板特化是文件范围。

答案 2 :(得分:0)

  

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

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

  

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

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