考虑模板参数的参数依赖外观(ADL)?

时间:2018-01-04 20:35:48

标签: c++ templates argument-dependent-lookup

我有几个名称空间,每个名称空间都有一个名为f的函数模板。

// f() and Widget
namespace A {
  struct Widget { };

  template <typename T>
  void func(const T&) { }
}

// f() and caller()
namespace B {
  template <typename T>
  void func(const T&) { }

  template <typename T>
  void caller(const T& t) {
    func(t); // error occurs here
  }
}

template <typename T>
class Wrap { };

int main() {
  Wrap<A::Widget> w{};
  B::caller(w); // triggers error
}

以上产生以下错误

error: call of overloaded ‘func(const Wrap<A::Widget>&)’ is ambiguous
     func(t);
     ~~~~^~~
note: candidate: void B::func(const T&) [with T = Wrap<A::Widget>]
   void func(const T&) { }
        ^~~~
note: candidate: void A::func(const T&) [with T = Wrap<A::Widget>]
   void func(const T&) { }
        ^~~~

如果A::func在全局命名空间中,为什么会考虑Wrap?我不应该B::caller致电B::func吗?

1 个答案:

答案 0 :(得分:2)

在模板的情况下,ADL并不仅仅考虑函数的参数。在这里,Wrap<A::Widget>作为B::caller的参数。由于caller位于namespace B,因此显然会考虑B::funcA::func被考虑的原因来自下面(强调添加)

  

N659 6.4.2 /(2.2) [basic.lookup.argdep]

     

如果T是类类型(包括联合),则其关联的类是:类本身;它所属的类   会员,如果有的话;及其直接和间接基类。其关联的命名空间是最里面的   包含其关联类的名称空间。 此外,如果T是一个类模板专业化,   其关联的名称空间和类还包括:名称空间和与之关联的类   为模板类型参数提供的模板参数的类型 [...]

由于A::WidgetWrap的模板参数,A也是Wrap<A::Widget>的关联命名空间

通过使用限定名称阻止ADL,可以按照预期编译此示例:

template <typename T>    
void caller(const T& t) {    
  B::func(t);      
}

或将函数名称括在paretheses中

template <typename T>    
void caller(const T& t) {    
  (func)(t);      
}