声明类时A
作为类(class)的 friend B
, 而 A
在匿名命名空间和 B
中定义在外部,一些编译器会产生错误“protected member inaccessible”,而其他编译器不会产生任何错误或警告。如果A
或 B
或者两者都是模板:
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>{});
}
-
A
和B
都是模板。然后 Intel icc 18: error#308: function "B<T>::bar [with T=int]" is inaccessible
, gcc 7.2: 没有错误, clang 5.0: 没有错误 -
A
B
时没有模板是模板:Intel icc 18:没有错误,gcc 7.2:错误:'void B<T>::bar() const [with T = int]' is protected within this context
, clang 5: 没有错误 -
A
是一个模板,而B
不是:英特尔 icc 18:错误#308
, gcc 7.2: 错误, clang 5: 没有错误 - 都不是
A
也不B
是模板:Intel icc 18:没有错误,gcc 7.2:错误,clang 5:没有错误 - 都不是
A
也不B
是模板(如 4.)但是A
的位置和B
已交换:英特尔 icc 18:错误#308
, gcc 7.2: error, clang 5: error:'bar' is a protected member of 'B'
-
A
和B
都是模板(如 1.)但是A
的位置和B
已交换:英特尔 icc 18:错误#308
, gcc 7.2: 没有错误, clang 5: error
请参阅编译器资源管理器中的示例:https://godbolt.org/g/6Zdr3c和 https://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.
因此参数化类 A
是 B
的友元,应该能够访问 B::bar
情况 5 有所不同。据我所知,友元声明在封闭范围内声明了一个新的参数化类 A
,它不同于未命名命名空间中的类 A
。
关于c++ - 匿名命名空间中模板化类的友元,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48270533/