My program behaves as I expect in C++20 mode of Visual Studio, but I need to make it run in C++17 mode, where the program changes its output.
After minimization, it looks as follows:
template <typename T>
int f() { return g(T{}); }
namespace {
struct A{
friend int g(const A &) { return 1; }
};
}
template <typename T>
int g(T&&) { return 2; }
int main() { return f<A>(); }
In C++20 mode the output from main()
is 1
, while in C++17 mode the output is 2
. Online demo: https://gcc.godbolt.org/z/h8b8qoGGj
I wonder what new feature of C++20 (absent in C++17) is responsible for the discrepancy of the result.
It has nothing to do with C++17 vs C++20.
The MSVC default name lookup behavior in templates is not standard-conforming. You need to give the /permissive-
flag to make it conform to the standard.
The /std:c++20
flag (or any /std:c++*
flag for a newer C++ revision) implicitly sets /permissive-
as well, while /std:c++17
and flags for earlier revisions do not.
In standard C++ the result 1
was always the only correct answer. The second overload of g
cannot be found by usual unqualified lookup for the call in f
because that lookup is performed from f
's point of definition where the overload is not declared yet. It also can't be found by ADL, because it is not placed in the same namespace as A
.