让我困惑的代码贴在这里:
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!
}
我正在尝试重载模板函数 (foo
)。如果我没理解错的话,模板代码只会在调用函数时生成。到那时,应该已经声明了该函数的重载版本(如您在代码中所见)并且名称查找应该已经在该重载版本上进行了选择。
我确定已经定义了重载版本,因为 static_assert(struct2Foo1 == 1)
返回 True
,这表明 foo(ns1::myStruct2&)
已定义。
另一个令人费解的事情是将重载版本放在 namespace ns1
中会导致模板函数选择重载版本。我知道这可能是由于 ADL 而发生的,但我不确定为什么 ADL 应该在同一个命名空间中直接重载时不起作用。
那么,当我将它放在同一命名空间中的模板声明下方时,为什么它没有选择重载版本?
最佳答案
从属名称的普通非限定查找仅考虑在模板定义上下文中找到的声明。因此,找不到 ns2
中的第二个 foo
。
依赖于参数的查找将考虑在定义或实例化上下文中找到的声明,但它只查找与参数关联的 namespace 和类,此处为 ns1
。因此,将找到稍后在 ns1
中声明的 foo
,但不会在 ns2
中找到。
关于c++ - C++ 模板的函数解析是如何完成的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51664782/