模板类的Passkey模式:友元与模板模板参数的编译冲突问题及解决技巧咨询
解决Clang下模板类Passkey模式的编译问题
你碰到的是Clang对模板友元声明的严格语法检查问题——GCC在这里的处理比较宽松,但我们只需要微调友元声明的写法就能让代码在Clang里正常编译。
问题根源
原始代码里的passkey模板中,友元声明template<typename...> friend class T;里的T会被Clang解析为友元模板自己的模板参数(哪怕这里没实际用到),这就遮蔽了外层passkey模板的模板参数T,触发了名字冲突的错误。
修复方案
只需要把友元模板的参数名改成和外层模板参数不同的名称即可,比如改成U...:
#include <iostream> template <template<typename...> class T> class passkey { private: // 将友元模板的参数名改为U...,避免遮蔽外层的T template<typename... U> friend class T; passkey() {} // noncopyable passkey(const passkey&) = delete; passkey& operator=(const passkey&) = delete; }; template<typename T> struct A { A(); }; void g(int i, passkey<A>) { std::cout << i; } template<typename T> A<T>::A(){g(42,{});} int main() { A<void> a; return 0; }
为什么这样能行?
修改后,友元模板的参数名U...和外层passkey的模板参数T不再同名,不会触发名字遮蔽问题。Clang会正确识别friend class T里的T就是外层passkey模板的模板参数,也就是我们要授权的模板类A。
这种写法完全符合C++标准,同时兼容GCC和Clang编译器,能完美保留Passkey模式的核心功能:只有A<T>的实例能调用g函数。
内容的提问来源于stack exchange,提问作者janou195
相关产品推荐
相关产品推荐

