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