提问者:小点点

非限定函数调用从错误的命名空间中选择函数


请考虑以下代码:

#include <iostream>

namespace A {
    struct Mine {};

    template <typename T1, typename T2>
    void foo(T1, T2)
    {
        std::cout << "A::foo" << std::endl;
    }
}

namespace B {
    template <typename T>
    void foo(T, T)
    {
        std::cout << "B::foo" << std::endl;
    }
}   

using namespace A;
using namespace B;
// or with the same effect:
//using A::foo;
//using B::foo;

int main()
{
    A::Mine a;
    foo(a, a);
}

程序打印b::foo而不是a::foo。 为什么它使用b::foo而不是a::foo

想象以下情况:您的库提供了一个名称空间a,其他一些库提供了名称空间b,其中包含一个与您的库同名的函数模板foo。 通常情况下,没有问题,因为可以使用限定调用或依赖于参数的查找来选择正确的版本。 但是,如果用户使用using声明将a::foob::foo引入同一作用域,则非限定调用并不含糊,但可能选择了错误的函数。

有没有一种方法更喜欢a::foo而不是b::foo,因为根据参数依赖的查找,应该选择a::foo? 在这种情况下你有什么建议?


共1个答案

匿名用户

它实际上在做正确的事情。 原因如下。

namespace A {
    struct Mine {};

    template <typename T1, typename T2>
    void foo(T1, T2)
    {
        std::cout << "A::foo" << std::endl;
    }
}

当有2个不同(或相同)类型的参数传递时,将匹配上述代码。 因为您定义了不同的T1T2(但它们也可以是相同的)。 但函数调用是

foo(a, a);

具有相同类型的两个参数。 现在在命名空间b中定义了一个方法foo,该方法具有两个相同类型的参数,如下所示

namespace B {
    template <typename T>
    void foo(T, T)
    {
        std::cout << "B::foo" << std::endl;
    }
}

因此,来自命名空间b的方法是匹配的,因为两个签名是不同的。

尝试添加以下代码

namespace C {
    template <typename T>
    void foo(T, T)
    {
        std::cout << "B::foo" << std::endl;
    }
}

最终将出现编译器错误,指定方法定义中存在歧义,然后必须使用a::foo(a,a)或您希望使用的任何名称空间手动解析foo的作用域。