In the unqualified name lookup, the standard gives the example 1.
struct T1 { struct U { int i; }; };
struct T2 { };
struct U1 {};
struct U2 {};
struct B {
using T = T1;
using U = U1;
operator U1 T1::*();
operator U1 T2::*();
operator U2 T1::*();
operator U2 T2::*();
};
template<class X, class T>
int g() {
using U = U2;
X().operator U T::*(); // #1, searches for T in the scope of X first
X().operator U decltype(T())::*(); // #2
return 0;
}
int x = g<B, T2>(); // #1 calls B::operator U1 T1::*
// #2 calls B::operator U1 T2::*
An unqualified name that is a component name ([expr.prim.id.unqual]) of a type-specifier or ptr-operator of a conversion-type-id is looked up in the same fashion as the conversion-function-id in which it appears. If that lookup finds nothing, it undergoes unqualified name lookup; in each case, only names that denote types or templates whose specializations are types are considered.
From the standard, it seems that the unqualified name U
and T
in operator U T::*
shall be looked up in the same way as operator U T::*
, i.e. looked up in the class scope B
, so that the first call should be operator U1 T1::*
. While the expression decltype(T())
will be instantiated to be T2
, the second call should be operator U1 T2::*()
.
It shocks me so that I made an experiment by adding codes below and compiling it:
#include <iostream>
B::operator U1 T1::*()
{
std::cout << __func__ << std::endl;
return nullptr;
}
B::operator U1 T2::*()
{
std::cout << __func__ << std::endl;
return nullptr;
}
B::operator U2 T1::*()
{
std::cout << __func__ << std::endl;
return nullptr;
}
B::operator U2 T2::*()
{
std::cout << __func__ << std::endl;
return nullptr;
}
int main() {}
However, the result is
operator U2 T2::*
operator U2 T2::*
instead of by the standard
operator U1 T1::*
operator U1 T2::*
Why the behavior differs with standard? I find no Defect Report about this.
My g++ version is
g++.exe (x86_64-win32-seh-rev1, Built by MinGW-Builds project) 14.2.0
This has to do with the fact that lookup for dependent conversion-type-ids was never properly specified prior to C++23; see CWG1500. The rule you cite was added by P1787R6, which completely overhauled the specification of name lookup in the standard. Because so many changes were made, it will take a while for GCC to finish implementing all of them.