我有一个带有私有构造函数的模板类,我希望该私有构造函数成为该类的所有模板化实例的朋友。以下在 g++ 11.4.0 下编译,但在 clang++ 版本 14.0.0-1ubuntu1.1 下失败
template <typename T>
class foo {
foo(T){}
template <typename U> friend foo<U>::foo(U);
public:
foo(){}
};
int main() {
foo<int> a{};
}
clang 给出错误
main.cpp:4:34: error: missing 'typename' prior to dependent type name 'foo<U>::foo'
template <typename U> friend foo<U>::foo(U);
^~~~~~~~~~~
typename
main.cpp:4:46: error: friends can only be classes or functions
template <typename U> friend foo<U>::foo(U);
我不认为
foo<U>::foo
是依赖类型名称,但无论如何按照建议添加类型名称会导致错误
main.cpp:4:55: error: friends can only be classes or functions
template <typename U> friend typename foo<U>::foo(U);
这似乎是编译器错误的集合。注意,gcc 实际上是无效的;如果您实际上尝试从假定的友好构造函数访问私有实体,它会拒绝:
template <typename T>
class foo {
foo(T);
template <typename U> friend foo<U>::foo(U);
public:
foo(){ foo<long> f(1l); }
// ^
// error: 'foo<T>::foo(T) [with T = long int]' is private within this context
};
int main() {
foo<int> a{};
}
但是,如果您从构造函数中删除参数列表,gcc 会奇怪地接受:
template <typename T>
class foo {
foo(T);
template <typename U> friend foo<U>::foo();
// ^ removed 'U'
public:
foo(){ foo<long> f(1l); }
};
int main() {
foo<int> a{};
}
此外,gcc 接受相关代码,其中被友好的类模板构造函数属于不同的类模板:
template<class T>
struct X {
X(T);
};
template<class T>
class C {
template<class U> friend X<U>::X(U);
C();
};
template<class T> X<T>::X(T) { C<int> c; }
X<int> x(1);
(也许 bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59798 相关;我不确定。)
gcc 还接受被友好的类模板构造函数属于不同的非模板类:
template<class T>
struct X {
X(T);
};
class C {
template<class U> friend X<U>::X(U);
C();
};
template<class T> X<T>::X(T) { C c; }
X<int> x(1);
最后一个代码是 clang 行为的线索;接受并带有警告:
警告:不支持友元类声明的依赖嵌套名称说明符“X::”;关闭“C”的访问控制 [-Wunsupported-friend]
所以,clang 在这方面缺少支持并且没有意识到这一点。
最简单的解决方法可能是遵循 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=42328#c4 的建议并与全班同学交朋友:
template <typename U> friend class foo;