代码之家  ›  专栏  ›  技术社区  ›  Hugh

为什么ADL找不到函数模板?

  •  79
  • Hugh  · 技术社区  · 15 年前

    C++规范的哪一部分限制了在相关联的命名空间集合中查找函数模板的依赖于参数的查找?换句话说,为什么最后一个电话 main 以下内容编译失败?

    namespace ns {
        struct foo {};
        template<int i> void frob(foo const&) {}
        void non_template(foo const&) {}
    }
    
    int main() {
        ns::foo f;
        non_template(f); // This is fine.
        frob<0>(f); // This is not.
    }
    
    4 回复  |  直到 7 年前
        1
  •  81
  •   Kornel Kisielewicz    15 年前

    这部分解释了它:

    C++标准03 :

    [注意:对于简单函数名,即使函数名在调用范围内不可见,也适用于依赖参数的查找(3.4.2)。这是因为调用仍然具有函数调用的语法形式(3.4.1)。但是,当使用带有显式模板参数的函数模板时,调用没有正确的语法形式,除非在调用点有一个具有该名称的函数模板可见。如果看不到这样的名称,则调用的语法格式不正确,并且不应用与参数相关的查找。如果某些这样的名称可见,则应用与参数相关的查找,并且可以在其他命名空间中找到其他函数模板。

    namespace A {
      struct B { };
      template<int X> void f(B);
    }
    namespace C {
      template<class T> void f(T t);
    }
    void g(A::B b) {
      f<3>(b);    //ill-formed: not a function call
      A::f<3>(b); //well-formed
      C::f<3>(b); //ill-formed; argument dependent lookup
                  // applies only to unqualified names
      using C::f;
      f<3>(b);    //well-formed because C::f is visible; then
                  // A::f is found by argument dependent lookup
    }
    
        2
  •  4
  •   marcinj    9 年前

    我想完善一点接受的答案。在操作问题中不清楚,但标准(由Kornel引用)的重要部分是(Emphasis Mine):

    但是当一个函数模板 显式模板参数 使用了,调用没有正确的语法形式

    因此,禁止依赖ADL和使用显式模板参数。不幸的是,使用非类型模板参数需要使用显式参数(除非它们具有默认值)。

    下面是显示这个的示例代码:

    [live]

    #include <string>
    #include <utility>
    
    namespace C {
      struct B { };
      template<class T> void f(T t){}
    }
    
    void g(C::B b) {
      f(b);           // OK
      //f<C::B>(b);   // ill-formed: not a function call, but only 
                      //  because explicit template argument were used
    
      std::string s;
      move(s);                      // OK
      //move<std::string&>(s);      // Error, again because 
                                    //  explicit template argument were used
      std::move<std::string&>(s);   // Ok
    }
    
    int main()
    {
     C::B b;
     g(b);
    }
    
        3
  •  2
  •   Chen Li    7 年前

    自从C++ 20以来,ADL还使用显式函数模板进行精细处理。建议如下: P0846R0: ADL and Function Templates that are not Visible :

    不是要求用户使用template关键字,而是建议对查找规则进行修订,以便普通查找不会产生结果,也不会查找一个或多个函数,后面跟着一个“<”的名称将被视为已找到函数模板名称,并将导致执行ADL。

    目前,只有GCC9实现了这个特性,所以您的示例可以编译。

    live demo .

        4
  •  0
  •   Community Mohan Dere    8 年前

    编辑:不,这不对。见 @Kornel's answer .


    我不太确定,但我查阅了Stroustrup的《C++程序设计语言》,我认为附录C部分是第138节。 可以 成为原因。

    自从 frob 是一个模板,人们可以想象专门为它 i=0 在你叫它之后。这意味着实现将留下两种可能的方法来选择 瞎调 调用时,它可以在实例化时选择它。 在翻译单元处理结束时。

    所以,我想问题是你能做到

    namespace ns {
        struct foo {};
        template<int i> void frob(foo const&) {}
    }
    
    int main() {
        ns::foo f;
        frob<0>(f);
        return 0;
    }
    
    namespace ns {
        template<> void frob< 0 >(foo const&) { /* Do something different*/ }
    }
    
    推荐文章