为什么这个C ++显式模板特化代码是非法的?

时间:2011-05-03 17:33:58

标签: c++ templates language-specifications explicit-specialization

(注意:我知道这是非法的,我正在寻找这种语言的原因。)

template<class c> void Foo();  // Note: no generic version, here or anywhere.

int main(){
  Foo<int>();
  return 0;
}

template<> void Foo<int>();

错误:

error: explicit specialization of 'Foo<int>' after instantiation

谷歌快速通过this citation of the spec,但这只提供了什么,而不是原因。

修改

有几个回复转发了这个论点(例如证实了我的推测),规则是这样的,因为否则会违反One Definition Rule (ODR)。然而,这是一个非常弱的论点,因为在这种情况下,它不适用于两个原因:

  1. 将显式专业化移动到另一个翻译单元可以解决问题并且似乎没有违反ODR(或链接器说的那样)。
  2. ODR的缩写形式(适用于函数)是指任何给定函数都不能有多个正文,而我不能。函数体的唯一定义是在显式特化中,因此对Foo<int>的调用无法定义模板的泛型特化,因为没有专门的泛型体。
  3. 对此事的猜测:

    关于为什么规则存在的猜测:如果第一行提供了一个定义(而不是声明),实例化后的显式特化将是一个问题,因为你会得到多个定义。但在这种情况下,唯一可见的定义是明确的专业化。

    奇怪的是,以下(或者我正在处理的实际代码中的类似内容)可以工作:

    档案A:

    template<class c> void Foo();
    
    int main(){
      Foo<int>();
      return 0;
    }
    

    档案B:

    template<class c> void Foo();
    
    template<> void Foo<int>();
    

    但总的来说,使用它开始创建一个意大利面条进口结构。

3 个答案:

答案 0 :(得分:5)

  

猜测为什么规则存在于   全部:如果第一行提供了   定义(而不是a   声明),一个明确的   实例化后的专业化   会是一个问题,因为你会   得到多个定义。但在这   案例,唯一的定义是   明确的专业化。

但你确实有多个定义。你已经定义了Foo&lt; int&gt;当你实例化它时,你尝试专门化int的模板函数,已经定义了。

int main(){
  Foo<int>();    // Define Foo<int>();
  return 0;
}

template<> void Foo<int>(); // Trying to specialize already defined Foo<int>

答案 1 :(得分:2)

此代码是非法的,因为在实例化后会出现显式特化。基本上,编译器首先看到了通用模板,然后它看到了它的实例化并专门化了具有特定类型的通用模板。之后,它看到了已经实例化的通用模板的特定实现。那么编译器应该做什么?回去重新编译代码?这就是不允许这样做的原因。

答案 2 :(得分:2)