代码之家  ›  专栏  ›  技术社区  ›  AnT stands with Russia

表达式中运算符的GCC和ADL

  •  9
  • AnT stands with Russia  · 技术社区  · 7 年前

    考虑这个代码示例

    template <typename T> struct S { T t; };
    
    template <class T> void foo(const S<T> &v)
    {
      bar(v.t);
    }
    
    namespace N
    {
      struct A {};
    } 
    
    void bar(const N::A &a) {}
    
    int main()
    {
      S<N::A> a;
      foo(a);    
    }
    

    代码无法在GCC和Clang中编译,因为常规查找和ADL都无法解析对的调用 bar foo . 这是意料之中的,因为 酒吧 电话只是 N 酒吧 找不到。一切照旧。

    但是,如果我把它改成

    template <typename T> struct S { T t; };
    
    template <class T> void foo(const S<T> &v)
    {
      +v.t;
    }
    
    namespace N
    {
      struct A {};
    } 
    
    void operator +(const N::A& a) {}
    
    int main()
    {
      S<N::A> a;
      foo(a);    
    }
    

    它突然开始在GCC中成功编译(同时,Clang拒绝了这两个版本的代码)。

    如果在代码的后一个版本中,我将调用更改为

    template <class T> void foo(const S<T> &v)
    {
      operator +(v.t);
    }
    

    它将再次无法在GCC中编译。所以,似乎有人对 表达式中的运算符 函数调用

    这是行为标准吗?我似乎在文档的文本中找不到它(搜索“关联的名称空间”),尽管我确实模糊地记得读过一些关于GCC的这种特性的内容。

    2 回复  |  直到 7 年前
        1
  •  9
  •   Barry    7 年前

    这是 gcc bug 51577 . 第二个测试用例几乎就是您的代码示例。

    [over.match.oper]/3 有:

    非成员候选集是对 operator@ 在表达式的上下文中,根据非限定函数调用([basic.lookup.argdep])中名称查找的常规规则,但忽略所有成员函数。

    在非限定函数调用中查找名称的常规规则不包括全局命名空间: [basic.lookup.argdep]/2

    如果 T

    N::A 是类类型,其关联的类是其自身,其关联的命名空间是 最里面的 N ,不是 :: .

        2
  •  3
  •   Jans    7 年前

    这个错误报告似乎是相关的 Bug 70099

    运算符是从属名称 [temp.dep]/1.3 :

    如果运算符的操作数是依赖类型的表达式,则该运算符还表示依赖名称。这些名称是未绑定的,并且在模板定义上下文和实例化点上下文中的模板实例化点(17.6.4.1)处查找

    通过 [temp.dep.res]

    N::A