【问题标题】:Why can't templates take function local types?为什么模板不能采用函数本地类型?
【发布时间】:2010-08-12 17:04:58
【问题描述】:

在 C++ 中,可以有一个采用函数本地类型的函数:

int main() {
  struct S { static void M(const S& s) { } };
  S s;
  S::M(s);
}

但不能有这样的模板:

template<typename T> void Foo(const T& t) { }

int main() {
  struct S { } s;
  Foo(s);   // Line 5: error: no matching function for call to 'Foo(main()::S&)'
}

14.3.1 paragraph 2 in the c++ standard.

没有链接的类型 [...] 不应用作模板类型参数的模板参数

为什么 C++ 不允许这样做?


到目前为止我听到的最好的解释是内部类型没有链接,这可能意味着将它们作为 arg 的函数必须没有链接。但是我没有理由看到模板实例化必须具有链接。


附言请不要只说“thats not allowed because the standard says it's not

【问题讨论】:

  • 没有充分的理由,C++0x 将删除此限制(但不是 p.s. 中链接的限制;我仍然不知道为什么不允许这样做)。跨度>
  • @Mike;简明扼要!

标签: c++ templates language-design


【解决方案1】:

我相信预见到的困难在于Foo&lt;T&gt; 的两个实例化实际上意味着完全不同的东西,因为T 对两者来说并不相同。相当多的模板的早期实现(包括 cfront 的)使用模板实例化存储库,因此当/如果发现该类型的实例化尚未在存储库中时,编译器可以自动实例化所需类型的模板。

为了使本地类型能够工作,存储库不仅能够存储实例化模板的类型,而且还必须执行一些操作,例如创建一个完整的“路径”到类型的实例化。虽然这可能是可能的,但我认为这被视为付出了很多额外的工作而几乎没有(如果有的话)真正的好处。

从那时起,规则已经发生了很大的变化,以至于编译器已经需要做一些几乎相同的事情,在不同的地方(包括跨 TU)查找(并合并)相同类型的实例化,以便 @987654323 的两个实例化@(例如)不要违反 ODR。基于这种认识,C++0x(当前草案)中的限制已经放松(您仍然不能在本地类型上实例化模板类,但您可以使用本地类型作为模板函数的参数) .

【讨论】:

  • @BCS:虽然这可能也是正确的,但它并不是那么多,它过去对编译器来说是更多的工作,因为它是 1) 大部分额外的工作无论如何,现在由于其他原因正在完成,并且 2) 编译 C++ 现在无论如何都非常复杂,人们更愿意接受增加更多的复杂性,只要它不太激烈。
  • §14.3.1 [temp.arg.type] 有几个将本地类型传递给类模板的示例。
【解决方案2】:

我猜这是因为它需要在函数范围内有效地实例化模板,因为这是这些类型可见的地方。但是,同时,模板实例化应该像在定义模板的范围内一样行事。我确信有可能以某种方式处理它,但如果我是对的,标准机构决定不把这个负担放在编译器编写者身上。

类似的决定是vector&lt;vector&lt;int&gt;&gt; 根据标准的语法无效的原因;检测该构造需要编译器词法分析器和解析器阶段之间的一些交互。然而,这种情况正在改变,因为 C++0x 标准人员发现所有编译器都会检测到它以发出合理的错误消息。

我怀疑,如果要证明允许这种构造很容易实现,并且不会在语言范围规则中引入任何歧义,那么您可能有一天会看到这里的标准也发生了变化。

【讨论】:

  • "Someday" 将在 C++0x 获得批准后立即出现,除非他们改变主意。最终草案取消了这一限制。
  • 我可以想象一个难以实现的编译器架构,但我也可以想到免费提供的编译器架构。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多