叮当虫?命名空间模板类的友元
clang bug? namespaced template class' friend
下面的代码不能在clang下编译,但可以在gcc和VS下编译:
template<typename T> class bar;
namespace NS
{
template<typename T>
class foo
{
foo() {}
template<typename U> friend class bar;
};
}
template<typename R>
class bar
{
public:
bar()
{
NS::foo<int> f;
}
};
int main(int, char **)
{
bar<int> b;
return 0;
}
main.cpp:20:22: error: calling a private constructor of class 'NS::foo<int>'
NS::foo<int> f;
^
main.cpp:8:9: note: implicitly declared private here
foo() {}
^
bar
应该可以访问foo
的私有构造函数,但看起来没有。如果我删除namespace NS
,它将编译。
代码对我来说看起来很好,但也许我误解了c++标准。哪个编译器是正确的?
我相信clang是对的。根据[namspace .memdef]/3:
在命名空间中首先声明的每个名称都是该命名空间的成员。中的
friend
声明非局部类首先声明类、函数、类模板或函数模板,友元是其成员
在你的例子中,这个名字似乎不是由friend
声明"首先声明"的。然而,在那一段的后面,强调我的:
如果
friend
声明中的名称既没有限定也没有模板id和声明是一个函数或一个详细的类型说明符,查找以确定实体是否具有不应考虑最内层封闭命名空间之外的任何作用域。
也就是这样的声明:
template<typename U> friend class bar;
将不会在namespace NS
之外寻找bar
,因此它不会找到您之前的声明。因此,它将类模板NS::bar<typename >
声明为foo
的friend
。您必须限定名称bar
,以便找到它:
template<typename U> friend class ::bar;
From cppreference:
在非局部类X中由友元声明引入的名称成为X的最内层封闭命名空间的成员,但它们确实是查找不可见(既不是不合格的也不是合格的)除非在命名空间范围内提供了匹配的声明在类定义之前或之后。这样的名字可以通过同时考虑命名空间和类的ADL。只有内心深处封闭命名空间是由友元声明来考虑的确定该名称是否与先前声明的名称冲突名字。void h(int); namespace A { class X { friend void f(X); // A::f is a friend class Y { friend void g(); // A::g is a friend friend void h(int); // A::h is a friend, no conflict with ::h }; }; // A::f, A::g and A::h are not visible at namespace scope // even though they are members of the namespace A X x; void g() { // definition of A::g f(x); // A::X::f is found through ADL } void f(X) {} // definition of A::f void h(int) {} // definition of A::h // A::f, A::g and A::h are now visible at namespace scope // and they are also friends of A::X and A::X::Y }
这不是标准,但总的来说是正确的。所以clang似乎是对的。
修改代码为
template<typename T> class bar;
namespace NS
{
template<typename T>
class foo
{
foo() {}
template<typename U> friend class ::bar;
};
}
template<typename R>
class bar
{
public:
bar()
{
NS::foo<int> f;
}
};
int main(int, char **)
{
bar<int> b;
return 0;
}
使用clang进行编译。问题似乎是名称空间查找。代码
template<typename U> friend class bar;
实际上声明了类NS::bar是NS::foo的友类,所以foo不应该受到影响。我的猜测是clang是符合标准的,代码不应该编译。
相关文章:
- C++ 17 个友元函数声明和内联命名空间
- 为什么 gcc 无法从其前向声明中检测到友元类命名空间?
- c++ 内联友元函数是否会导致命名空间之间的名称隐藏?
- 友元类指向不同命名空间中同名的类
- 跨命名空间的友元类和不同的.H 文件
- 在 c++ 中定义命名空间中模板类的友元函数时出现问题
- 匿名命名空间中模板化类的友元
- 另一个命名空间和 CRTP 中的模板友元函数
- 类内定义的友元函数的调试标志中的命名空间
- 关于友元函数定义和命名空间范围
- 将命名空间声明为类的友元
- 模板对象的模板友元函数和命名空间
- 命名空间内类的友元函数
- 为什么我的类友元函数无法访问具有命名空间的受保护成员?
- 命名空间内出现错误 C2248 友元类
- 如何在gtest中使用带有命名空间的友元类
- 哪个命名空间确实包含此友元函数的声明
- 不同命名空间中的友元运算符
- 命名空间内的友元函数声明/定义
- 具有嵌套命名空间内的友元函数的模板类