实参取决之查找规则(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()
 
实参取决之查找规则(argument-dependent lookup):等您坐沙发呢!