C ADL模板如何修改以适应特定需求?

摘要:什么是 ADL ADL(Argument Dependent Lookup),参数依赖查找,明确的意思是依赖参数的函数查找,即对于函数调用,不仅会依照常规的名称查找规则,还会在函数参数所在的命名空间内查找。 我们常用的 std::cout
什么是 ADL ADL(Argument Dependent Lookup),参数依赖查找,明确的意思是依赖参数的函数查找,即对于函数调用,不仅会依照常规的名称查找规则,还会在函数参数所在的命名空间内查找。 我们常用的 std::cout << "..." 其实就是一个 ADL 的例子,std::cout,查看一下 STL 的代码,它是std::basic_ostream<char, std::char_traits<char>>,而这个类只定义了针对算术类型和指针类型的 operator<< 并没有定义针对 const char * 的版本,使用编译器的跳转功能跳转到 << 的调用,其实是 template<class _Traits> std::basic_ostream<char, _Traits> operator<<(std::basic_ostream<char, _Traits> &, const char *) 也就是说这个调用其实等价于 operator<<(std::cout, "..."),注意 operator<< 前并没有使用 std:: 来指定查找位置,而这个对于 std::operator<< 的调用能顺利解析而不会触发 '没有与操作数匹配的操作符' 错误,正是由于 ADL 发挥了作用:第一个参数 std::cout 所在的命名空间 std 被加入到对 operator<< 的查找空间内,从而匹配到针对 const char * 的 operator<< 。 ADL + 模板 当函数参数是模板时,查找空间会扩展到参数模板所在的命名空间以及模板实参的命名空间: 代码 namespace space { struct A{}; template<typename T> struct TpA{}; template<typename T, template<typename> class Tp> void foo(Tp<T> &){} } template<typename T> struct TpB{}; space::TpA<int> tai; foo(tai);//通过TpA找到foo TpB<space::A> tba; foo(tba);//通过A找到foo 根据模板实参自动选择调用函数 ADL + 模板很容易就能实现根据模板实参调用不同函数的功能: 代码 namespace spaceA { struct A{}; void foo(A &){} } namespace spaceB { struct B{}; void foo(B &){} } ... template<typename T> void dispatch(T &value) { foo(value); } spaceA::A a; dispatch(a);//绑定到spaceA::foo(spaceA::A &) spaceB::B b; dispatch(b);//绑定到spaceB::foo(spaceB::B &) 只要约定好接口,dispatch函数就能根据实例化类型来调用,可以实现松散的代码结构,并且函数的绑定在编译期进行。使用继承体系也能实现相同的需求,但是函数的调用是运行时解析。可以根据实际情况决定选用哪种方案。