You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

带非类型模板参数的模板类如何友元同参数模板类?

带非类型模板参数的模板类的友元声明正确语法

当然可以将带非类型模板参数的模板类声明为友元,你的代码编译错误源于友元声明的语法错误,导致友元关系未正确建立,进而无法访问Big的protected成员。

错误原因分析

  1. 友元声明语法错误:你在Big类中写的template <config> friend class Small;是非法的。模板参数列表需要指定参数的类型和名称,而config是Big的非类型模板参数(是一个值,不是类型),所以编译器报错'config' is not a type。
  2. 访问权限问题:因为友元关系没建立,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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 19:47:25