什么是“破碎”与Microsoft Visual C ++的两阶段模板实例化? [英] What exactly is "broken" with Microsoft Visual C++'s two-phase template instantiation?

查看:114
本文介绍了什么是“破碎”与Microsoft Visual C ++的两阶段模板实例化?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

阅读SO的问题,意见和答案,我听说MSVC没有正确实现两阶段模板查找/实例化。

Reading questions, comments and answers on SO, I hear all the time that MSVC doesn't implement two-phase template lookup / instantiation correctly.

理解到目前为止,MSVC ++只是对模板类和函数进行基本的语法检查,并且不检查模板中使用的名称是否至少已声明或沿着这些行。

From what I understand so far, MSVC++ is only doing a basic syntax check on template classes and functions and doesn't check that names used in the template have atleast been declared or something along those lines.

这是正确的吗?

推荐答案

我只是从我的注意书

int foo(void*);

template<typename T> struct S {
  S() { int i = foo(0); }
  // A standard-compliant compiler is supposed to 
  // resolve the 'foo(0)' call here (i.e. early) and 
  // bind it to 'foo(void*)'
};

void foo(int);

int main() {
  S<int> s;
  // VS2005 will resolve the 'foo(0)' call here (i.e. 
  // late, during instantiation of 'S::S()') and
  // bind it to 'foo(int)', reporting an error in the 
  // initialization of 'i'
}

上面的代码应该在标准的C ++编译器中编译。然而,MSVC(2005以及2010 Express)将报告错误,因为两阶段查找的执行不正确。

The above code is supposed to compile in a standard C++ compiler. However, MSVC (2005 as well as 2010 Express) will report an error because of incorrect implementation of two-phase lookup.

如果你看起来更近,这个问题实际上是两层的。表面上,显而易见的事实是,微软的编译器不能为非依赖表达式 foo(0)执行早期(第一阶段)查找。但是它之后它做的并不是第二个查找阶段的正确实现。

And if you look closer, the issue is actually two-layered. At the surface, it is the obvious fact that Microsoft's compiler fails to perform early (first phase) lookup for a non-dependent expression foo(0). But what it does after that does not really behave as a proper implementation of the second lookup phase.

语言规范清楚地表明,在第二个查找阶段ADL提名的命名空间得到扩展,在定义点和实例化点之间累积了额外的声明。同时,非ADL查找(即普通不合格名称查找)不是通过第二阶段扩展的 - 它仍然看到那些并且只有那些在第一阶段可见的声明。

The language specification clearly states that during the second lookup phase only ADL-nominated namespaces get extended with additional declarations accumulated between the point of definition and point of instantiation. Meanwhile, non-ADL lookup (i.e. ordinary unqualified name lookup) is not extended by the second phase - it still sees those and only those declarations that were visible at the first phase.

这意味着在上面的例子中,编译器不应该在第二阶段看到 void foo(int)。换句话说,MSVC的行为不能由仅仅MSVC推迟所有查找直到第二阶段来描述。

That means that in the above example the compiler is not supposed to see void foo(int) at the second phase either. In other words, the MSVC's behavior cannot be described by a mere "MSVC postpones all lookup till the second phase". What MSVC implements is not a proper implementation of the second phase either.

为了更好地说明问题,请考虑以下示例

To better illustrate the issue, consider the following example

namespace N {
  struct S {};
}

void bar(void *) {}

template <typename T> void foo(T *t) {
  bar(t);
}

void bar(N::S *s) {}

int main() {
  N::S s;
  foo(&s);
}

请注意,即使 bar code>调用模板定义是在第二个查找阶段解析的一个 dependent 表达式,它仍然应该解析为 void bar(void *)。在这种情况下,ADL不帮助编译器找到 void bar(N :: S * s),而正常的非限定查找不应该被扩展第二阶段,因此不应该看到 void bar(N :: S * s)

Note that even though bar(t) call inside the template definition is a dependent expression resolved at the second lookup phase, it should still resolve to void bar(void *). In this case ADL does not help the compiler to find void bar(N::S *s), while the regular unqualified lookup is not supposed to get "extended" by the second phase and thus is not supposed to see void bar(N::S *s) either.

,Microsoft的编译器解析调用 void bar(N :: S * s)。这是不正确的。

Yet, Microsoft's compiler resolves the call to void bar(N::S *s). This is incorrect.

问题仍然存在于它在VS2015的原始荣耀。

The problem is still present in its original glory in VS2015.

这篇关于什么是“破碎”与Microsoft Visual C ++的两阶段模板实例化?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆