如何为C++模板完成功能解析?

Min*_* Lê 3 c++ templates overloading function overload-resolution

困扰我的代码发布在这里:

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!
}
Run Code Online (Sandbox Code Playgroud)

我试图重载模板化的函数(foo).如果我理解正确,只有在调用函数时才会生成模板代码.到那时,应该已经声明了函数的重载版本(正如您在代码中看到的那样),并且名称查找应该已经在该重载版本上获得了.

我确定已经定义了重载版本因为static_assert(struct2Foo1 == 1)返回True,这表明foo(ns1::myStruct2&)已经定义了.

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

那么,为什么当我把它放在同一命名空间中的模板声明下面时,它没有拿起重载版本?

T.C*_*.C. 5

对从属名称的普通非限定查找仅考虑在模板定义上下文中找到的声明.你的第二个foons2所以没有发现.

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