实参取决之查找规则(argument-dependent lookup)

实参取决之查找规则(argument-dependent lookup)
调用类类型形参的函数时,如果该函数与该类类型定义在同一命名空间,会将该函数加入到候选函数,如果有多个候选函数形参类型匹配时,那么会有二义性。如果有二义性,普通函数优先于函数模板实例。!!!!! 20190823
例子:

#include <iostream>                                                                                                                                                                            
namespace WidgetStuff
{
    template<typename T>
    class WidgetImpl { };

    template<typename T>
    class Widget
    {
    public:
        void swap(Widget &other)
        {
            using std::swap;
            swap(pImpl, other.pImpl);
            std::cout << "WidgetStuff::Widget::swap" << std::endl;
        }
    private:
        WidgetImpl<T> pImpl;
    };
}

namespace WidgetStuff
{   
    //这里定义会与全局命名空间的swap模板函数实参推断冲突
    //调用类类型形参的函数时,如果该函数与该类类型定义在同一命名空间,会将该函数加入到候选函数,
    //如果有多个候选函数形参类型匹配时,那么会有二义性。如果有二义性,普通函数优先于函数模板实例。!!!!!  20190823
    //template<typename T>
    //void swap(Widget<T> &a, Widget<T> &b)
    //{
    //  a.swap(b);
    //  std::cout << "WidgetStuff::Widget test run" << std::endl;
    //}
}

template<typename T>
void swap(WidgetStuff::Widget<T> &a, WidgetStuff::Widget<T> &b)
{
    a.swap(b);
    std::cout << "::swap test run" << std::endl;
}

namespace NS
{
    template<typename T>
    void fun(const T &)
    {
        std::cout << typeid(T).name() << std::endl;
    }
}

namespace NS2
{
    class Tmp
    {
    };
    //template<typename Tmp>
    void fun(Tmp)
    {
        std::cout << "NS2::fun(tmp)" << std::endl;
    }
    void fun()
    {
        std::cout << "NS2::fun()" << std::endl;
    }
    template<typename T>
    void dosome(const T &obj) {
        std::cout <<"NS2::dosome" << std::endl;
    }
}

void fun()
{
    std::cout << "::fun()" << std::endl;
}

using NS2::Tmp;                                                                                                                                                                                
void fun(Tmp)
{
    std::cout << "::fun(tmp)" << std::endl;
}
void dosome(const Tmp &obj)
{
    using NS::fun;  //NS::fun(Tmp)屏蔽全局作用域fun
    //全局作用域fun(Tmp)不会与NS2::fun(Tmp)二义性,因为它被上面using声明屏蔽
    //NS::fun(Tmp)和NS2::fun(Tmp)都是候选函数且有二义性,但NS2::fun(Tmp)是普通函数,优先函数模板实例
    //所以这里调用与类类型Tmp同命名空间中的NS2::fun(Tmp) 20190823
    fun(obj);
}

using NS::fun;
int main()
{
    //using NS::fun;    //这里如果using声明会屏蔽全局命名空间的fun()函数,导致下面的fun()没有匹配定义
    WidgetStuff::Widget<int> wg1, wg2;
    swap(wg1, wg2);

    NS2::Tmp t;
    dosome(t); //普通函数优先于NS2中函数模板实例。
    fun();
}
运行结果:
WidgetStuff::Widget::swap
::swap test run
NS2::fun(tmp)
::fun()
 
喜欢 0
分享