带非类型模板参数的模板类如何友元同参数模板类?
带非类型模板参数的模板类的友元声明正确语法
当然可以将带非类型模板参数的模板类声明为友元,你的代码编译错误源于友元声明的语法错误,导致友元关系未正确建立,进而无法访问Big的protected成员。
错误原因分析
- 友元声明语法错误:你在
Big类中写的template <config> friend class Small;是非法的。模板参数列表需要指定参数的类型和名称,而config是Big的非类型模板参数(是一个值,不是类型),所以编译器报错'config' is not a type。 - 访问权限问题:因为友元关系没建立,
Small::doit()访问big.burger时触发protected成员访问错误。
正确的友元声明方式
根据需求,有两种常见的正确写法:
方式1:仅让同参数的Small<config>实例成为Big<config>的友元
如果只需要和当前Big实例使用相同模板参数的Small实例拥有访问权限,直接声明特定模板实例为友元即可:
template <Configuration config> class Big { // 声明同参数的Small实例为友元 friend class Small<config>; // 其余代码保持不变 };
方式2:让所有Small模板实例成为Big的友元
如果需要所有Small的模板实例都能访问Big的protected成员,需要完整声明友元模板的参数列表:
template <Configuration config> class Big { // 声明整个Small模板为友元 template <Configuration C> friend class Small; // 其余代码保持不变 };
修正后的完整代码
以下是采用方式1的完整可编译代码,同时修复了main函数中非类型模板参数必须为编译期常量的问题:
#include <iostream> struct Configuration { static constexpr int foo = 12; }; // forward declaration of template class Big template <Configuration config> class Big; template <Configuration config> class Small { public: Small(Big<config>& big): big(big) { } void doit() { std::cout << big.burger + config.foo << "\n"; } protected: Big<config>& big; }; template <Configuration config> class Big { friend class Small<config>; public: Big(): small(*this) { } void doit() { small.doit(); } protected: Small<config> small; double burger = 42.3; }; int main([[maybe_unused]] int argc, [[maybe_unused]] char *argv[]) { constexpr Configuration conf{}; // 非类型模板参数必须是编译期常量 Big<conf> big; big.doit(); }
编译运行结果
使用g++ --std=c++20 friend-template-class.cc -o friend-template-class编译后,运行程序会输出:
54.3
内容的提问来源于Stack Exchange,提问作者Eric Smith
相关产品推荐
相关产品推荐

