Reputation: 90
The code that baffles me is posted here:
namespace ns1 {
struct myStruct1 {};
struct myStruct2 {};
}
namespace ns2 {
template <typename T>
constexpr int foo(T& x) {
return 1;
}
// If the two functions below are switched, it returns 2 correctly
template <typename T>
constexpr int fooCaller(T& x) {
return foo(x);
}
constexpr int foo(ns1::myStruct2& x) {
return 2;
}
}
// If the below is uncommented, it also returns 2 correctly
/*
namespace ns1 {
constexpr int foo(myStruct2& x) {
return 2;
}
}
*/
int main() {
ns1::myStruct1 struct1;
constexpr int struct1Foo1 = ns2::foo(struct1);
static_assert(struct1Foo1 == 1);
constexpr int struct1Foo2 = ns2::fooCaller(struct1);
static_assert(struct1Foo2 == 1);
ns1::myStruct2 struct2;
constexpr int struct2Foo1 = ns2::foo(struct2);
static_assert(struct2Foo1 == 2);
constexpr int struct2Foo2 = ns2::fooCaller(struct2);
static_assert(struct2Foo2 == 2); // Assertion fails, returns 1 instead!
}
I am trying to overload a templated function (foo
). If I understand correctly, the template code would be generated only when the function is called. By that time, the overloaded version of the function should have been declared (as you can see in the code) and name lookup should have picked up on that overloaded version.
I'm sure that the overloaded version have been defined because static_assert(struct2Foo1 == 1)
returns True
, which indicates that foo(ns1::myStruct2&)
has been defined.
Another baffling thing is placing the overloaded version in namespace ns1
causes the templated function to choose the overloaded version instead. I understand that this might have happened thanks to ADL, but I am not sure why ADL should work when directly overloading in the same namespace does not.
So why is it not picking up the overloaded version when I placed it below the template declaration in the same namespace?
Upvotes: 3
Views: 106
Reputation: 137301
Ordinary unqualified lookup of dependent names only considers declarations found in the template definition context. Your second foo
in ns2
is therefore not found.
Argument-dependent lookup will consider declarations found in either the definition or the instantiation context, but it only looks into namespaces and classes associated with the arguments, here, ns1
. Thus, a foo
declared later in ns1
will be found, but not one in ns2
.
Upvotes: 5