Incorrect overload resolution for 2-argument functions - c++

Let's take the following example program:
#include <cmath>
namespace half_float
{
template<typename T> struct half_expr {};
struct half : half_expr<half>
{
operator float() const;
};
template<typename T> half sin(const half_expr<T>&);
template<typename T> half atan2(const half_expr<T>&, const half_expr<T>&);
}
using namespace std;
using half_float::half;
int main()
{
half a, b;
half s = sin(a);
half t = atan2(a, b);
}
In VS 2010 this compiles just fine (ignore the obvious linker errors for now). But in VS 2012 this gives me:
error C2440: 'conversion' : cannot convert from 'float' to
'half_float::half'
So it seems overload resolution doesn't pick the version from namespace half_float (which ADL should accomplish), but the one from std using the implicit conversion to float. But the strange thing is, that this only happens for the atan2 call and not the sin call.
In the larger project, where this error actually first occured to me it also occurs for other 2-argument functions (or rather those with 2 half arguments), like fmod, but not for any 1-argument function. Likewise in the larger project it also works fine for gcc 4.6/4.7 and clang 3.1 without error, though I didn't test this SSCCE version explicitly there.
So my question is, is this erroneous behaviour on VS 2012's side (given that it only happens for 2012 and only for the 2-argument function), or did I oversee some subtleties in the overload resolution rules (which can indeed get a bit tricky, I guess)?
EDIT: It also happens if I'm directly using namespace half_float or put the whole thing in global namespace directly. Likewise does it also happen if I'm not using namespace std, but this is rather the VS-implementation putting the math functions in global namespace.
EDIT: It happens both with the original VC 2012 compiler as well as the November 2012 CTP of it.
EDIT: Although I'm not completely sure it is really a violation of the standard in the strictest sense, I have filed a bug for it based on the findings in my answer, since it is at least inconsistent to the definition of the 1-argument functions and deserves further investigation by the VS-Team.

I think I found the cause. The C++ standard says in section 26.8 [c.math], that for the mathematical functions of the C library,
there shall be additional overloads sufficient to ensure:
If any argument corresponding to a double parameter has type long double, then all arguments corresponding to double parameters are
effectively cast to long double.
Otherwise, if any argument corresponding to a double parameter has type double or an integer type, then all arguments corresponding to
double parameters are effectively cast to double.
Otherwise, all arguments corresponding to double parameters are effectively cast to float.
Which can also be seen in the atan2 documentation.
Those overloads are provided by VS 2012 through the use of a general function template of the form:
template<typename T,typename U> common_float_type<T,U>::type atan2(T, U);
So we have a template function whose instantiation would involve an implicit conversion (from half& to const half_expr<half>&) and a template function which can be instantiated directly. Thus the latter is preferred. This doesn't happen for the 1-argument functions because for those there only has to be a general version for integral arguments, which is provided by VS 2012 for only those using a std::enable_if of std::is_integral.
But I think the standard is a bit unclear about the fact that those "additional overloads" are to be provided only for builtin types. So in the end I'm still not sure if VS 2012 strictly violates the standard with its overly generic functions or if it is a viable implementation option to provide those.
EDIT: As it seems, there is already defect report 2086 for the standard's unclear wording and a fix is on it's way, limiting the requirement for those additional overloads to only arithmetic types. Since this seems to have always been the original intent (and realized by nearly all existing implementations) and it was merely the wording that was unclear, I would indeed regard this a bug in VS 2012's implementation.

I just tried your code, and I figured out what was wrong with it.
Since you haven't implemented half::sin and half::atan2, the linker will throw an error anyway. So if you implement the methods half::sin and half::atan2, that should solve it (I implemented them by letting them return an empty half, which is, of course, meaningless).
After I took that step (providing a (meaningless) implementation of the two required methods), the error messages almost magically disappeared.
Maybe this isn't the solution to your problem, as I'm using GCC, and not VS.
EDIT: I just tried the sample I used with G++ with visual studio, which gave me a peculier error message. Provided the strangeness of the error, and the code working with GCC, I must conclude that this is a bug in VC2012.

A workaround is to specialise _Common_float_type for half and half_expr to be an undefined type, so that SFINAE gets rid of the VS2012 version of atan2.
namespace std {
template<class T1, class T2>
struct _Common_float_type<half_float::half_expr<T1>, half_float::half_expr<T2>>;
template<class T2>
struct _Common_float_type<half_float::half, half_float::half_expr<T2>>;
template<class T1>
struct _Common_float_type<half_float::half_expr<T1>, half_float::half>;
template<>
struct _Common_float_type<half_float::half, half_float::half>;
}
Note that you have to specialise for all four combinations of half and half_expr, because template specialisation doesn't consider base classes.

Related

Compile-time error in uninstanciated function template

My understanding of function templates has always been: if they contain invalid
C++ and you don't instanciate them, your project will compile fine.
However, the following code:
#include <cstdio>
#include <utility>
template <typename T>
void contains_compile_time_error(T&& t) {
int j = nullptr;
}
int main() {}
Compiles with:
x86-64 gcc 11.2 and flag -std=c++20;
x64 msvc v19.31 and flag /std:c++20;
and does not with x86-64 clang 14.0.0 (with flags -std=c++{11,14,17,20}):
error: cannot initialize a variable of type 'int' with an rvalue of type 'std::nullptr_t'
int j = nullptr;
^ ~~~~~~~
1 error generated.
Even more confusing to me, the following code:
#include <cstdio>
#include <utility>
namespace ns {
struct S {};
template <typename T>
void apply(T&& t) {
//print(std::forward<T>(t));
ns::print(std::forward<T>(t));
}
void print(S const&) { std::puts("S"); }
} // namespace ns
int main() {}
Does not compile with:
x86-64 gcc 11.2 and flag -std=c++20;
x64 msvc v19.31 and flag /std:c++20;
x86-64 clang 14.0.0 and flags -std=c++{11,14,17,20};
(all of them complaining that print is not a member of 'ns') but does compile with x64 msvc v19.31 /std:c++17.
If I call unqualified print, then the code compiles with all the above compilers.
So, my questions are:
is my understanding of function templates wrong?
why do the above compilers behave differently with the code snippets I posted?
Edit 0: as per Frank's comment, x64 msvc v19.31 /std:c++17 /permissive- fails to compile function template apply where I call the qualified ns::print.
My understanding of function templates has always been: if they contain invalid C++ and you don't instanciate them, your project will compile fine.
Nope, if the code in the template is invalid, then so is the program.
But what does "invalid C++" mean? You can have syntactically valid C++ that is still invalid semantically, and the semantics of C++ are highly contextual.
So there's multiple levels of "valid" that can be checked at different times during compilation, based on the available information. Critically, there are things that can theoretically be checked early, but are potentially unreasonably difficult. Because of this, compilers are allowed some leeway when it comes to validating the semantics of template definitions. However, whether the code is broken or is not ambiguous, it's a compiler's ability to detect broken code that is.
why do the above compilers behave differently with the code snippets I posted?
As far as int j = nullptr is concerned:
The program is technically ill-formed, but the diagnostics is optional. So The code is broken, but GCC is not breaking compliance by letting it through.
For example, if S only had private constructors, then print(std::forward<T>(t)) would be flaggable as being broken since there is no possibly T that would make it valid. However, requiring compilers to be smart enough to determine this in all cases would be kind of mean.
For print():
Lookups are a bit of a different matter, there are hard rules that are supposed to be followed.
There are three types of lookups involved here.
Qualified lookups, such as ns::print
Unqualified lookups not involving template parameters, which you'd get if you tried print(S{});
Unqualified lookups involving template parameters, such as print(std::forward<T>(t));
Lookups are deferred for the third category, but must still be performed the same as non-template functions for the other two.
Note that the code still needs to be syntactically valid, even in the case of deferred lookups, hence why typename needs to be added when doing a dependent lookup of a type.
And as for MSVC allowing ns::print: That compiler is not compliant by default on this (and other) aspect of the standard. You need to use the /permissive- compiler flag to enforce compliance.

Does the order of the template funcation declaration matter in g++? [duplicate]

Reading questions, comments and answers on SO, I hear all the time that MSVC doesn't implement two-phase template lookup / instantiation correctly.
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.
Is this correct? What am I missing?
I'll just copy an example from my "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 (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'
}
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.
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.
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.
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);
}
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.
Yet, Microsoft's compiler resolves the call to void bar(N::S *s). This is incorrect.
The problem is still present in its original glory in VS2015.
The Clang project has a pretty good writeup of two-phase lookup, and what the various implementation differences are: http://blog.llvm.org/2009/12/dreaded-two-phase-name-lookup.html
Short version: Two phase lookup is the name for the C++ standard defined behavior for name lookup within template code. Basically, some names are defined as dependent (the rules for which are a bit confusing), these names must be looked up when instantiating the template, and independent names must be looked up when parsing the template. This is both hard to implement (apparently), and confusing for developers, so compilers tend to not implement it to the standard. To answer your question, it looks like Visual C++ delays all lookups, but searches both the template context and the instantiation context, so it accepts a lot of code that the standard says it shouldn't. I'm not sure whether it doesn't accept code it should, or worse, interprets it differently, but it seems possible.
Historically gcc didn't implement the two-phase name lookup correctly either. It's apparently very difficult to get to, or at least there wasn't much incentive...
gcc 4.7 claims to implement it correctly, at last
CLang aims at implementing it, baring bugs, it's done on ToT and will get into 3.0
I don't know why VC++ writers never chose to implement this correctly, implementation of a similar behavior on CLang (for microsoft compabitility) hints that there might be some performance gain to delaying the instantiation of templates at the end of the translation unit (which does not mean implementing the look-up incorrectly, but make it even more difficult). Also, given the apparent difficulty of a correct implementation it may have been simpler (and cheaper).
I would note that VC++ is first, and foremost, a commercial product. It is driven by the need to satisfy its clients.
short answer
Disable language extensions with /Za
longer answer
I was investigating this issue lately and was amazed that under VS 2013 following example from standard [temp.dep]p3 produces 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(x.a).name() << std::endl;
}
will print:
type of a: int
while it should print double. The solution to make VS standard conformant is to disable language extensions (option /Za), now type of x.a will resolve to double, also other cases of using dependent names from base classes will be standard conformant. I am not sure if this enables two phase lookup.
[Update Jul-2019] Its also true for vs 2015 - https://rextester.com/YOH81784, but VS2019 shows correctly double. According to this article Two-phase name lookup support comes to MSVC, it was fixed since VS 2017.
Now that MSVC has most of two-phase name lookup implemented, I'm hoping this blog post answers this question completely: Two-phase name lookup comes to MSVC (VC++ blog)

c++11 tie name clash with boost

I am trying to migrate some code from boost::tuple to std::tuple but I'm getting some weird errors: after I invoke using namespace std (and never boost), I expect an unqualified tie to resolve to std::tie. However, this seems to fail when the tuple contains a boost container pointer, for example.
#include <tuple>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/identity.hpp>
#ifdef USE_STD
#define TIE std::tie
#else
#define TIE tie
#endif
typedef boost::multi_index_container<
int,
boost::multi_index::indexed_by<
boost::multi_index::ordered_non_unique<
boost::multi_index::identity<int>
>
>
> Set;
std::tuple< int, int* > make_i_ptr();
std::tuple< int, Set* > make_set();
int main()
{
using namespace std;
int i;
int* i_ptr;
Set* set_ptr;
tie(i, i_ptr) = make_i_ptr();
TIE(i, set_ptr) = make_set();
return 0;
}
If I compile with g++ -std=c++0x -c test.cpp -DUSE_STD, all is well. However, without -D USE_STD, I get compile errors suggesting g++ tries to use boost::tuples::tie. I'm using g++ 4.8.1 and boost 1.55.0. Do you think this is a bug with boost? Or is there some spec I'm missing?
Lookup is complicated. The problem as others have mentioned is Argument Dependent Lookup or ADL. The rules for ADL were added to allow the definition of operators in the same namespace as the types they refer to, and enabling lookup to find those operators when present. This was later extended to all other functions in the process of standarization.
The issue here is that tie(...) is a function call. The compiler will attempt regular lookup from the point of use (inside main) it will move out to the enclosing namespace. The using directive will add ::std into the lookup search when it hits the root namespace (common ancestor of ::std and ::main). At that point, since the identifier resolves to a function, ADL will kick in.
ADL adds the namespaces associated to the arguments of the function call, which in this case is boost:: (fundamental types like int have no associated namespaces). At this point the compiler sees two declarations of tie: std::tie and boost::tie, causing ambiguity.
As you already know the solution is to qualify the call to std::tie (which I would advice that you use even without this issue). Regarding the comment:
If ADL makes it resolve to boost::tie for... "my convenience" and then the compilation fails, shouldn't that be a clue to the compiler that it picked the wrong function?!
I don't know what the exact error you are getting is (I don't use boost, and I don't know what possible overloads of std::tie it contains). If the problem is indeed one of ambiguity, the problem is that the compiler cannot resolve the identifier, and cannot continue the process. At that point it stops and asks for the programmer to resolve it. If the error is that it uniquely picked boost::tie and it later failed in the assignment, it means that theres is an overload of boost::tie that is a better match than std::tie and that was selected. At a later time the assignment from std::tuple may have failed, but the compiler cannot know whether the problem was during lookup, or whether it is the assignment itself (did you intend on assigning that variable? maybe a different one?) so again it fails and tells you what the problem is.
Note that in general the process of compilation is always moving forward, the compiler does not backtrack to double guess its own decisions*. There is a set of rules, and those rules are applied at each step. If there is ambiguity, compilation stops, if not, then there is a single best candidate and this point is resolved, moving to the next. Attempting to go back to undo decisions would turn the compilation process into something painfully slow (the number of paths that could be taken would be exponential).
* As always there are some exceptions but those are just exceptions, notably during overload resolution if a template is picked as the best candidate but substitution of type arguments fail, it is discarded and the next best candidate is chosen.

No instance of function template remove_if matches argument list

I am trying to remove whitespaces from a string
line.erase(remove_if(line.begin(), line.end(), isspace), line.end());
But Visual Studio 2010 (C++ Express) tells me
1 IntelliSense: no instance of function template "std::remove_if" matches the argument list d:\parsertry\parsertry\calc.cpp 18
Full Source
Why is that? A simple piece of code
int main() {
string line = "hello world 111 222";
line.erase(remove_if(line.begin(), line.end(), isspace), line.end());
cout << line << endl;
getchar();
return 0;
}
Verifies the function works?
Funny thing is despite that, it runs giving correct result.
Don't question Intellisense, sometimes it's better to just ignore it. The parser or the database got screwed up somehow, so it doesn't work correctly anymore. Usually, a restart will fix the problem.
If you really want to know if the code is ill-formed, well, just hit F7 to compile.
Your source code compiles without even a warning with Visual C++ 11.0 (the compiler that ships with Visual Studio 2012).
Intellisense uses its own rules and isn't always reliable.
That said, your use of isspace is Undefined Behavior for all character sets except original 7-bit ASCII. Which means the heavily upvoted answer that you took it from, is just balderdash (which should not surprise). You need to cast the argument to (the C library's) isspace to unsigned char to avoid negative values and UB.
C99 §7.4/1 (from the N869 draft):
The header <ctype.h> declares several functions useful for testing and mapping
characters.
In all cases the argument is an int, the value of which shall be
representable as an unsigned char or shall equal the value of the macro EOF. If the
argument has any other value, the behavior is undefined.
A simple way to wrap the C function is
bool isSpace( char const c )
{
typedef unsigned char UChar;
return !!::isspace( UChar( c ) );
}
Why the typedef?
It makes the code easier to adapt when
you already have such a typedef, which is not uncommon;
it makes the code more clear; and
it avoids a C syntax cast, thereby avoiding a false positive when searching for such via a regular expression or other pattern matching.
But, why the !! (double application of the negation operator)? Considering there’s an automatic implicit conversion from int to bool? And, if one absolutely feels that the conversion should be explicit, shouldn’t it be a static_cast, and not !!?
Well, the !! avoids a silly-warning from the Visual C++ compiler,
“warning C4800: 'int' : forcing value to bool 'true' or 'false' (performance warning)”
and a static_cast doesn’t stop that warning. It’s good practice to quench that warning, and since Visual C++ is the main C++ compiler on the most used system, namely Windows, better do this in all code meant to be portable.
Oh, OK, but, since the function must be wrapped anyway, then … why use the old C libary isspace (single argument) function, when the <locale> header provides a far more more flexible C++ (two arguments) isspace function?
Well, first and foremost, the old C isspace function is the one used in the question, so that’s the one discussed in this answer. I have focused on discussing just how to not do this incorrectly, that is, how to avoid Undefined Behavior. Discussing how to do it right brings it to a whole different level.
But regarding the in-practice, the C++ level function of the same name can be considered to be broken, since with g++ compilers until recently (and perhaps even with g++ 4.7.2, i haven't checked lately) only the C locale mechanism worked, and the C++ level one didn't, in Windows. It may have been fixed since g++ now supports wide streams, I don’t know. Anyway, there C library isspace function, in addition to being in-practice more portable and generally working in Windows, is also simpler and, I believe, more efficient (although for efficiency one should always MEASURE if it is deemed important!).
Thanks to James Kanze for asking (essentially) the questions above, in the comments.
What is isspace? Depending on the includes headers and the compiler
you are using, it's likely that your code won't even compile. (I don't
know about IntelliSense, but it's possible that it's looking at all of
the standard headers, and sees the ambiguity.)
There are two isspace functions in the standard, and one is a
template. Passing a function template to a template argument of another
function template does not give the compiler nearly enough information
to be able to do template argument deduction: in order to resolve the
overload of isspace, it has to know the type expected by the
remove_if, which it only knows after template argument deduction has
succeeded. And to do template argument deduction on remove_if, it has
to know the types of the arguments, which means the type of isspace,
which it will only know once it has been able to resolve the overload on
it.
(I'm actually surprised that your little bit of code compiles: you
obviously include <iostream>, and typically, <iostream> will include
<locale>, which will bring in the function template isspace.)
Of course, the function template isspace must be called with two
arguments, so if it were ever chosen, the instantiation of remove_if
wouldn't compile (but the compiler does not try to instantiate
remove_if until it has chosen a function). And the isspace in
<ctype.h> will result in undefined behavior if passed a char, so you
can't use it. The usual solution is to create a set of predicate
objects for your tool box, and use them. Something like the following
should work if you're only concerned with char:
template <std::ctype<char>::mask m>
class Is : public std::unary_function<char, bool>
{
std::locale myLocale; // To ensure lifetime of following...
std::ctype<char> const* myCType;
public:
Is( std::locale const& loc = std::locale() )
: myLocale( loc )
, myCType( &std::use_facet<std::ctype<char> >( myLocale ) )
{
}
bool operator()( char ch ) const
{
return myCType->is( m, ch );
}
};
typedef Is<std::ctype_base::space> IsSpace;
It's trivial to add the additional typedef's so you get the complete
set, and I've found it useful to add an IsNot template as well. It's
simple, and it avoids all of the surrounding issues.

What exactly is "broken" with Microsoft Visual C++'s two-phase template instantiation?

Reading questions, comments and answers on SO, I hear all the time that MSVC doesn't implement two-phase template lookup / instantiation correctly.
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.
Is this correct? What am I missing?
I'll just copy an example from my "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 (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'
}
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.
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.
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.
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);
}
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.
Yet, Microsoft's compiler resolves the call to void bar(N::S *s). This is incorrect.
The problem is still present in its original glory in VS2015.
The Clang project has a pretty good writeup of two-phase lookup, and what the various implementation differences are: http://blog.llvm.org/2009/12/dreaded-two-phase-name-lookup.html
Short version: Two phase lookup is the name for the C++ standard defined behavior for name lookup within template code. Basically, some names are defined as dependent (the rules for which are a bit confusing), these names must be looked up when instantiating the template, and independent names must be looked up when parsing the template. This is both hard to implement (apparently), and confusing for developers, so compilers tend to not implement it to the standard. To answer your question, it looks like Visual C++ delays all lookups, but searches both the template context and the instantiation context, so it accepts a lot of code that the standard says it shouldn't. I'm not sure whether it doesn't accept code it should, or worse, interprets it differently, but it seems possible.
Historically gcc didn't implement the two-phase name lookup correctly either. It's apparently very difficult to get to, or at least there wasn't much incentive...
gcc 4.7 claims to implement it correctly, at last
CLang aims at implementing it, baring bugs, it's done on ToT and will get into 3.0
I don't know why VC++ writers never chose to implement this correctly, implementation of a similar behavior on CLang (for microsoft compabitility) hints that there might be some performance gain to delaying the instantiation of templates at the end of the translation unit (which does not mean implementing the look-up incorrectly, but make it even more difficult). Also, given the apparent difficulty of a correct implementation it may have been simpler (and cheaper).
I would note that VC++ is first, and foremost, a commercial product. It is driven by the need to satisfy its clients.
short answer
Disable language extensions with /Za
longer answer
I was investigating this issue lately and was amazed that under VS 2013 following example from standard [temp.dep]p3 produces 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(x.a).name() << std::endl;
}
will print:
type of a: int
while it should print double. The solution to make VS standard conformant is to disable language extensions (option /Za), now type of x.a will resolve to double, also other cases of using dependent names from base classes will be standard conformant. I am not sure if this enables two phase lookup.
[Update Jul-2019] Its also true for vs 2015 - https://rextester.com/YOH81784, but VS2019 shows correctly double. According to this article Two-phase name lookup support comes to MSVC, it was fixed since VS 2017.
Now that MSVC has most of two-phase name lookup implemented, I'm hoping this blog post answers this question completely: Two-phase name lookup comes to MSVC (VC++ blog)