What exactly is “broken” with a two-step instance of the Microsoft Visual C ++ template?

Reading questions, comments and answers to SO, I hear all the time that MSVC does not implement two-phase search / template creation correctly.

From what I understand so far, MSVC ++ only performs basic syntax checking in the classes and functions of templates and does not check that the names used in the template are declared or something like these strings.

It is right? What am I missing?

+36
c ++ instantiation visual-c ++ templates
Jun 08 2018-11-11T00:
source share
5 answers

I just copy the example from "notebook"

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 (ie early) and // bind it to 'foo(void*)' }; void foo(int); int main() { S<int> s; // VS2005 will resolve the 'foo(0)' call here (ie // late, during instantiation of 'S::S()') and // bind it to 'foo(int)', reporting an error in the // initialization of 'i' } 

The above code should compile in the standard C ++ compiler. However, MSVC (2005 as well as 2010 Express) will report an error due to improper implementation of the two-phase search.




And if you look closer, the problem is actually two-layer. At first glance, it is obvious that the Microsoft compiler does not perform an early (first stage) search for the independent expression foo(0) . But what he does after that does not really behave as the correct implementation of the second phase of the search.

The language specification clearly states that in the second stage of the search, only extended ADL namespaces are expanded with additional declarations accumulated between the definition point and the instantiation point. Meanwhile, a non-ADL search (i.e., a regular unqualified name search) is not expanded by the second phase - it still sees those and only those ads that were visible in the first stage.

This means that in the above example, the compiler should not see void foo(int) in the second phase. In other words, the behavior of MSVC cannot be described simply "MSVC postpones the entire search until the second phase." What the MSVC implements is not a proper implementation of the second phase.

To better illustrate this 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); } 

Please note that even if the call to bar(t) inside the template definition is a dependent expression allowed in the second phase of the search, it should still solve void bar(void *) . In this case, ADL does not help the compiler find the void bar(N::S *s) , while the regular unskilled search should not be "expanded" by the second phase and, therefore, should not also see the void bar(N::S *s)

However, the Microsoft compiler allows the call to void bar(N::S *s) . This is not true.

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

+40
Jun 08 2018-11-11T00:
source share

There is a pretty good two-phase search entry in the Clang project, and what are the various differences in implementation: http://blog.llvm.org/2009/12/dreaded-two-phase-name-lookup.html

Short version: two-step search is the name for C ++ standard behavior for finding a name in the template code. In principle, some names are defined as dependent (the rules for which are a little confused), these names should be looked at when creating a template instance, and independent names should look when analyzing a template. This is difficult to implement (apparently) and confusing for developers, so compilers, as a rule, do not apply it to the standard. To answer your question, it seems that Visual C ++ delays all search queries, but searches for both the template context and the context context, so it takes a lot of code, which, according to the standard, should not. I'm not sure if it does not accept code that should or, even worse, interpret it differently, but it seems possible.

+21
Jun 08 2018-11-11T00:
source share

Historically, gcc also did not implement a two-phase name lookup. It seems to be very difficult to get there, or at least there wasn’t much incentive ...

  • gcc 4.7 claims to implement it correctly , finally
  • The purpose of the CLAN is to implement it, prohibit errors, do it on ToT and get into 3.0

I don’t know why the authors of VC ++ never chose this correctly, the implementation of a similar behavior on CLang (for compatibility with Microsoft) suggests that there may be some performance gain to delay the creation of templates at the end of the translation unit (which does not mean that the search was not performed correctly, but make it even more difficult). In addition, given the apparent difficulty of implementing correctly, it may have been easier (and cheaper).

I would like to note that VC ++ is the first and, above all, commercial product. This is due to the need to satisfy their customers.

+8
Jun 08 2018-11-11T00:
source share

short answer

Disable language extensions with / Za

long answer

I recently researched this problem and was amazed that in VS 2013 the following example from the standard [temp.dep] p3 gives the wrong result:

 typedef double A; template<class T> class B { public: typedef int A; }; template<class T> struct X : B<T> { public: A a; }; int main() { X<int> x; std::cout << "type of a: " << typeid(xa).name() << std::endl; } 

will print:

 type of a: int 

while it should print double . The decision to make VS standard compatible is to disable language extensions (the / Za option), now the xa type will double, and other cases of using dependent names from the base classes will be standard compatible. I am not sure if this allows a two-phase search.

[July-2019 update] This is also true for 2015 - https://rextester.com/YOH81784 , but VS2019 shows the correct double . According to this article, support for searching by a two-phase name is included in the MSVC , it has been fixed since VS 2017.

+5
Dec 16 '14 at 9:42
source share

Now that MSVC has most of the two-phase name lookup, I hope this blog post fully answers this question: A two-step name lookup for MSVC comes in (VC ++ blog)

+3
Nov 17 '17 at 19:08
source share



All Articles