使用Microsoft Visual C ++的两阶段模板实例化到底是什么“打破”?

使用Microsoft Visual C ++的两阶段模板实例化到底是什么“打破”?

在SO上阅读问题,评论和答案,我一直听说MSVC没有正确地实现两阶段模板查找/实例化。

据我所知,到目前为止,MSVC ++只对模板类和函数进行了基本的语法检查,并没有检查模板中使用的名称是否至少被声明了或者沿着这些行。

它是否正确?我错过了什么?


蛊毒传说
浏览 444回答 3
3回答

慕姐4208626

我只是从我的“笔记本”中复制一个例子int&nbsp;foo(void*);template<typename&nbsp;T>&nbsp;struct&nbsp;S&nbsp;{ &nbsp;&nbsp;S()&nbsp;{&nbsp;int&nbsp;i&nbsp;=&nbsp;foo(0);&nbsp;} &nbsp;&nbsp;//&nbsp;A&nbsp;standard-compliant&nbsp;compiler&nbsp;is&nbsp;supposed&nbsp;to&nbsp; &nbsp;&nbsp;//&nbsp;resolve&nbsp;the&nbsp;'foo(0)'&nbsp;call&nbsp;here&nbsp;(i.e.&nbsp;early)&nbsp;and&nbsp; &nbsp;&nbsp;//&nbsp;bind&nbsp;it&nbsp;to&nbsp;'foo(void*)'};void&nbsp;foo(int);int&nbsp;main()&nbsp;{ &nbsp;&nbsp;S<int>&nbsp;s; &nbsp;&nbsp;//&nbsp;VS2005&nbsp;will&nbsp;resolve&nbsp;the&nbsp;'foo(0)'&nbsp;call&nbsp;here&nbsp;(i.e.&nbsp; &nbsp;&nbsp;//&nbsp;late,&nbsp;during&nbsp;instantiation&nbsp;of&nbsp;'S::S()')&nbsp;and &nbsp;&nbsp;//&nbsp;bind&nbsp;it&nbsp;to&nbsp;'foo(int)',&nbsp;reporting&nbsp;an&nbsp;error&nbsp;in&nbsp;the&nbsp; &nbsp;&nbsp;//&nbsp;initialization&nbsp;of&nbsp;'i'}上面的代码应该在标准的C ++编译器中编译。但是,MSVC(2005以及2010 Express)将报告错误,因为两阶段查找的实现不正确。如果你仔细观察,问题实际上是两层的。从表面上看,显而易见的事实是,Microsoft的编译器无法对非依赖表达式执行早期(第一阶段)查找foo(0)。但它之后的作用并不像第二个查找阶段的正确实现那样。语言规范明确指出,在第二个查找阶段,只有在定义点和实例化点之间累积的附加声明才会扩展ADL指定的命名空间。同时,非ADL查找(即普通的非限定名称查找)不会被第二阶段扩展 - 它仍然可以看到那些以及仅在第一阶段可见的那些声明。这意味着在上面的例子中,编译器也不应该void foo(int)在第二阶段看到。换句话说,仅仅“MSVC将所有查找推迟到第二阶段”不能描述MSVC的行为。MSVC实现的不是第二阶段的正确实现。为了更好地说明问题,请考虑以下示例namespace&nbsp;N&nbsp;{ &nbsp;&nbsp;struct&nbsp;S&nbsp;{};}void&nbsp;bar(void&nbsp;*)&nbsp;{}template&nbsp;<typename&nbsp;T>&nbsp;void&nbsp;foo(T&nbsp;*t)&nbsp;{ &nbsp;&nbsp;bar(t);}void&nbsp;bar(N::S&nbsp;*s)&nbsp;{}int&nbsp;main()&nbsp;{ &nbsp;&nbsp;N::S&nbsp;s; &nbsp;&nbsp;foo(&s);}请注意,即使bar(t)模板定义中的调用是在第二个查找阶段解析的依赖表达式,它仍应解析为void bar(void *)。在这种情况下,ADL无法帮助编译器查找void bar(N::S *s),而常规的非限定查找不应该被第二阶段“扩展”,因此也不应该看到void bar(N::S *s)。然而,微软的编译器解决了对它的调用void bar(N::S *s)。这是不正确的。这个问题仍然存在于VS2015的原始荣耀中。

婷婷同学_

从历史上看,gcc也没有正确实现两阶段名称查找。这显然很难达到,或者至少没有太大的激励......gcc的4.7索赔正确地执行它,最后CLang旨在实现它,禁止错误,它在ToT上完成并将进入3.0我不知道为什么VC ++编写者从未选择正确实现这一点,在CLang上实现类似的行为(对于微软的兼容性)暗示在翻译单元末端延迟模板的实例化可能会有一些性能提升(并不意味着错误地实施查找,但使其更加困难)。此外,鉴于正确实施的明显困难,它可能更简单(并且更便宜)。我会注意到VC ++首先是商业产品。它是满足客户需求的驱动力。
打开App,查看更多内容
随时随地看视频慕课网APP