c++ - 匿名命名空间中模板化类的友元

标签 c++ templates namespaces language-lawyer friend

声明类时A作为类(class)的 friend B , 而 A在匿名命名空间和 B 中定义在外部,一些编译器会产生错误“protected member inaccessible”,而其他编译器不会产生任何错误或警告。如果AB或者两者都是模板:

namespace {
  template <class T>
  struct A {
    template <class BB>
    void foo(BB const& b) { b.bar(); }
  };
} // end anonymous namespace

template <class T>
class B {
  template <class> friend struct A;

protected:
  void bar() const {}
};

int main() {
  A<int> a;
  a.foo(B<int>{});
}
  1. AB都是模板。然后 Intel icc 18: error #308: function "B<T>::bar [with T=int]" is inaccessible , gcc 7.2: 没有错误, clang 5.0: 没有错误
  2. A B 时没有模板是模板:Intel icc 18:没有错误,gcc 7.2:错误:'void B<T>::bar() const [with T = int]' is protected within this context , clang 5: 没有错误
  3. A是一个模板,而 B不是:英特尔 icc 18:错误 #308 , gcc 7.2: 错误, clang 5: 没有错误
  4. 都不是A也不B是模板:Intel icc 18:没有错误,gcc 7.2:错误,clang 5:没有错误
  5. 都不是A也不B是模板(如 4.)但是 A 的位置和 B已交换:英特尔 icc 18:错误 #308 , gcc 7.2: error, clang 5: error: 'bar' is a protected member of 'B'
  6. AB都是模板(如 1.)但是 A 的位置和 B已交换:英特尔 icc 18:错误 #308 , gcc 7.2: 没有错误, clang 5: error

请参阅编译器资源管理器中的示例:https://godbolt.org/g/6Zdr3chttps://godbolt.org/g/BRqf78对于案例 6.

那么,什么是正确的行为呢?哪个编译器是正确的?

最佳答案

据我从标准判断,给定的代码在情况 1-4 中是正确的,并且应该在没有诊断的情况下编译:

未命名命名空间的定义 (7.3.1.1:1) 声明未命名命名空间定义等同于使用翻译单元唯一的名称定义命名命名空间,然后使用 using 指令导入此命名空间。

这将使 A 的声明在全局范围内可访问,并根据段落 11.3:9

A name nominated by a friend declaration shall be accessible in the scope of the class containing the friend declaration.

因此参数化类 AB 的友元,应该能够访问 B::bar

情况 5 有所不同。据我所知,友元声明在封闭范围内声明了一个新的参数化类 A,它不同于未命名命名空间中的类 A

关于c++ - 匿名命名空间中模板化类的友元,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48270533/

相关文章:

Ruby 模板 if else 语句

c++ - 我可以按类类型访问什么类型的集合,并在必要时返回找不到

c++ - 异步 C++11 中 future 的析构函数

c++ - C++中的递归列表文件不会进入所有子目录

c++ - 模板函数在模板对象上执行成员回调而不提供它的实例

c++ - 为什么 std::stable_partition 在没有显式命名空间规范的情况下进行编译

namespaces - 您如何在 Riak 中组织存储桶?

php - 了解 php 命名空间以及 fatal error : undefined constant 的原因

c++ - 在 C++ 中获取均匀分布的随机整数的标准方法是什么?

c++ - Raspberry Pi C++ 段错误