Search code examples
c++templatesvisual-c++c++17c++20

Argument-dependent lookup in Visual C++


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.


Solution

  • 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.