为什么模板不能采用函数本地类型?

发布于 2024-09-14 06:18:03 字数 982 浏览 8 评论 0 原文

在 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 C++ 标准中的第 2 段。

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

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


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


ps 请不要只是说“这是不允许的,因为标准说不是

In C++ it's OK to have a funcction that takes a function local type:

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

but not OK to have a template that does:

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.

A type with no linkage [...] shall not be used as a template-argument for a template type-parameter

Why does C++ disallow that?


The best explanation I've heard so far it that inner types have no linkage and that this could imply that a function that takes them as an arg must have no linkage. But there is no reason I can see that a template instantiation must have linkage.


p.s. Please don't just say "thats not allowed because the standard says it's not"

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

一抹淡然 2024-09-21 06:18:03

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

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

从那时起,规则已经发生了足够的变化,以至于编译器已经被要求做一些几乎等效的事情,在不同位置(包括跨 TU)查找(并合并)同一类型的实例化,以便 foofoo< 的两个实例化。 int>(例如)不违反 ODR。基于该实现,C++0x(当前草案)中放宽了限制(您仍然无法通过本地类型实例化模板类,但可以使用本地类型作为模板函数的参数) 。

I believe the difficulty that was foreseen was with two instantiations of Foo<T> actually meaning entirely different things, because T wasn't the same for both. Quite a few early implementations of templates (including cfront's) used a repository of template instantiations, so the compiler could automatically instantiate a template over a required type when/if it was found that an instantiation over that type wasn't already in the repository.

To make that work with local types, the repository wouldn't just be able to store the type over which the template was instantiated, but instead it would have to do something like creating a complete "path" to the type for the instantiation. While that's probably possible, I think it was seen as a lot of extra work for little (if any) real benefit.

Since then, the rules have changed enough that the compiler is already required to do something that's just about equivalent, finding (and coalescing) instantiations over the same type at different places (including across TUs) so that two instantiations of foo<int> (for example) don't violate the ODR. Based on that realization, the restriction has been loosened in (the current draft of) C++0x (you still can't instantiate a template class over a local type, but you can use a local type as parameter to a template function).

入画浅相思 2024-09-21 06:18:03

我猜测这是因为它需要在函数范围内有效地实例化模板,因为这是此类类型可见的地方。然而,与此同时,模板实例化应该表现得好像它们在定义模板的范围内一样。我确信可以以某种方式处理这个问题,但如果我是对的,标准机构决定不给编译器编写者带来这种负担。

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

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

I'm guessing it is because it would require the template to be effectively instantiated within the scope of the function, since that is where such types are visible. However, at the same time, template instantiations are supposed to act as if they are in the scope in which the template is defined. I'm sure this it's possible to deal with that somehow, but if I'm right the standards body decided not to put that burden on compiler writers.

A similar decision was the reason vector<vector<int>> is invalid syntax per the standard; detecting that construction requires some interaction between compiler lexer and parser phases. However, that's changing, because the C++0x standards folk found that all the compilers are detecting it anyway to emit sane error messages.

I suspect that if it were to be demonstrated that allowing this construction was trivial to implement, and that it didn't introduce any ambiguities in the language scoping rules, you might someday see the standard changed here too.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文