C++ 模板的函数解析是如何完成的?

How is function resolution done for C++ templates?

让我困惑的代码贴在这里:

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) returns True,这表明已经定义了foo(ns1::myStruct2&)

另一个令人费解的事情是将重载版本放在 namespace ns1 中会导致模板函数选择重载版本。我知道这可能是由于 ADL 而发生的,但我不确定为什么 ADL 在同一命名空间中直接重载时不能工作。

那么,当我将重载版本放在同一命名空间中的模板声明下方时,为什么它没有选择重载版本?

从属名称的普通非限定查找仅考虑在模板定义上下文中找到的声明。因此找不到 ns2 中的第二个 foo

依赖于参数的查找将考虑在定义或实例化上下文中找到的声明,但它只查找名称空间和与参数关联的 类,此处为 ns1。因此,将找到稍后在 ns1 中声明的 foo,但不会在 ns2.

中找到