考虑以下代码:

#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
想象一下以下情况:您的库提供了一个 namespace A,而其他一些库提供了 namespace B,其中包括一个功能模板,该功能模板的名称与您的库相同。通常,没有问题,因为可以使用限定调用或依赖于参数的查找来选择正确的版本。但是,如果用户使用foo声明将A::fooB::foo引入相同的作用域,则不合格的调用不会产生歧义,但可能会选择错误的函数。
有一种方法可以选择using而不是A::foo,因为应该根据依赖于参数的查询选择B::foo?在这种情况下,您有什么建议?

最佳答案

它实际上是在做正确的事情。这就是原因。

namespace A {
    struct Mine {};

    template <typename T1, typename T2>
    void foo(T1, T2)
    {
        std::cout << "A::foo" << std::endl;
    }
}
当有2个不同(或相同)类型的参数传递时,上述代码将匹配。因为您对T1T2的定义不同(但它们也可以相同)。但是函数调用是
foo(a, a);
具有相同类型的两个参数。
现在,在foo中定义了具有2个相同类型参数的namespace B方法,如下所示
namespace B {
    template <typename T>
    void foo(T, T)
    {
        std::cout << "B::foo" << std::endl;
    }
}
因此namespace B中的方法是匹配的,因为两个签名都不同。
尝试添加以下代码
namespace C {
    template <typename T>
    void foo(T, T)
    {
        std::cout << "B::foo" << std::endl;
    }
}
并最终导致编译器错误,在方法定义中指定歧义,然后您必须使用A::foo(a,a)之类的东西或希望使用的任何命名空间来手动解析foo的范围。

10-08 10:47
查看更多