C++ 匿名命名空间内运算符的模板重载解析

C++ 匿名命名空间内运算符的模板重载解析,c++,templates,gcc,language-lawyer,argument-dependent-lookup,C++,Templates,Gcc,Language Lawyer,Argument Dependent Lookup,简短问题:操作员是否有特殊的模板查找规则,用于通过内部链接进行重载解析,或者底部的代码是否是GCC中操作员的模板重载解析错误 细节:我不粘贴一段代码,而是让您了解我的推理。让我们从一些简单的代码开始: #include <iostream> template<typename T> struct A{ T b; }; struct B{}; template<typename T> void foo (const A<T>&a) {

简短问题:操作员是否有特殊的模板查找规则,用于通过内部链接进行重载解析,或者底部的代码是否是GCC中操作员的模板重载解析错误

细节:我不粘贴一段代码,而是让您了解我的推理。让我们从一些简单的代码开始:

#include <iostream>

template<typename T> struct A{ T b; };
struct B{};

template<typename T> 
void foo (const A<T>&a) { foo(a.b); } 
void foo (const B&) { std::cout << "hello"; }

int main(){
  A<B> b;
  foo(b);
}
代码现在无法编译。Clang表示
错误:对函数“foo”的调用在模板定义中既不可见,也无法通过参数相关查找找到该函数
和GCC
模板参数推断/替换失败

这是因为
foo(const B&)
是在
foo
之后定义的,并且没有外部链接,如中所述:

[基本链接] 未命名命名空间或在未命名命名空间中直接或间接声明的命名空间 内部联系。所有其他名称空间都有外部链接

[温度点] 依赖于模板参数的表达式的实例化上下文是一组声明 在同一翻译单元中的模板专用化实例化点之前声明外部链接

[临时副总裁候选人] 对于后缀表达式为从属名称的函数调用, 使用常用的查找规则(3.4.1, 3.4.2)但以下情况除外:

  • 对于使用非限定名称查找(3.4.1)的查找部分,仅限模板中的函数声明 找到定义上下文

  • 对于查找部分,请使用 关联的名称空间(3.4.2),仅在 模板定义上下文或模板实例化 可以找到上下文

现在,使用操作符的情况也一样:

struct ostream {} cout; 
template<typename T> struct A{ T t; };
struct B{};

namespace {
template<typename T>
ostream& operator<< (ostream& out, const A<T>&v) 
  { return out << v.t; }
ostream& operator<< (ostream& out, const B&) 
  { return out; }
}

int main(){
  A<B> a;
  cout << a; 
}
struct ostream{}cout;
模板结构A{T;};
结构B{};
名称空间{
模板

ostream&operator这肯定是gcc中的一个bug。下面的代码正确地打印了带有叮当声的
right
,但带有gcc的
error

#include <iostream>

template<typename T> struct A{ T t; };
struct B{};
struct C : public B{};

std::ostream& operator<< (std::ostream& out, const B&) 
  { return out << "right"; }

namespace {
template<typename T>
std::ostream& operator<< (std::ostream& out, const A<T>&v) 
  { return out << v.t; }

std::ostream& operator<< (std::ostream& out, const C&) 
  { return out << "wrong"; }
}

int main(){
  A<C> a;
  std::cout << a;
}
#包括
模板结构A{T;};
结构B{};
结构C:公共B{};

std::ostream&operator可能与此相关,感谢您指出@T.C。GCC中的运算符查找确实有一些问题。我仍然将其作为一个单独的错误进行归档,因为上下文似乎不同,但根本原因可能相同。我通过切换定义顺序,获得了在GCC上编译的
foo
代码。这与您期望的相符吗?这里是。@AustinMullins:是的,符合。这里的要点是,根据标准,带有
foo
的示例格式不正确,对于
运算符也应该如此
#include <iostream>

template<typename T> struct A{ T t; };
struct B{};
struct C : public B{};

std::ostream& operator<< (std::ostream& out, const B&) 
  { return out << "right"; }

namespace {
template<typename T>
std::ostream& operator<< (std::ostream& out, const A<T>&v) 
  { return out << v.t; }

std::ostream& operator<< (std::ostream& out, const C&) 
  { return out << "wrong"; }
}

int main(){
  A<C> a;
  std::cout << a;
}