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

标签 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) { foo(a.b); } 
void foo (const B&) { std::cout << "hello"; }

int main(){
  A<B> b;
  foo(b);
}

以上打印 "hello" , 一切都很好。

现在让我们把两个 foo在匿名命名空间中:

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

代码现在无法编译。 Clang 说 error: call to function 'foo' that is neither visible in the template definition nor found by argument-dependent lookup和 GCC template argument deduction/substitution failed .

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

[basic.link] An unnamed namespace or a namespace declared directly or indirectly within an unnamed namespace has internal linkage. All other namespaces have external linkage.

[temp.point] The instantiation context of an expression that depends on the template arguments is the set of declarations with external linkage declared prior to the point of instantiation of the template specialization in the same translation unit.

[temp.dep.candidate] For a function call where the postfix-expression is a dependent name, the candidate functions are found using the usual lookup rules (3.4.1, 3.4.2) except that:

  • For the part of the lookup using unqualified name lookup (3.4.1), only function declarations from the template definition context are found.

  • For the part of the lookup using associated namespaces (3.4.2), only function declarations found in either the template definition context or the template instantiation context are found.

现在使用运算符也是一样的:

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; 
}

GCC (4.7/4.8/4.9) 现在对代码非常满意,并通过 -Wall -Wextra -pedantic -ansi 给出零警告而clang提示'operator<<'foo 一样.

我没有发现标准中的运算符重载查找有任何异常,所以我认为这是 GCC 中的一个错误(功能?),但模板解析规则并不容易,所以我想我可以在提交错误之前检查这里。

您可以实时查看此代码 here .

最佳答案

这绝对是 gcc 中的一个错误。下面的代码用 clang 正确打印 right 但用 GCC 打印 wrong

#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;
}

报告 here .

关于c++ - 匿名命名空间内运算符的模板重载解析,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28904035/

相关文章:

c++ - 如何删除在C++中另一个线程中创建的对象

c++ - 获取 Eigen C++ 库 Vector 的最大系数的位置

c++ - 我无法正确删除 vector 中的元素

c++ - 循环中的重复随机数

c++ - 从模板继承 : scope error?

mongodb - 蒙戈.h : No such file or directory

c++ - constexpr 与 std::array - "Non-type template argument is not a constant expression"

ruby-on-rails - 在 Rails 模板中读取文件

c - 简单 printf() 的奇怪垃圾输出

用GCC编译一个C程序,使其可以在linux中使用所有cpu核