来自另一个命名空间的友元函数

Friend function from another namespace

/** module.h */
#pragma once

class A {
  friend void helpers::logValue(const A &);
  int _val;

public:
  A() {}
};

namespace helpers {
  static void logValue(const A &a) {
    std::cout << a._val;  // <== ERROR: '_val' is not accessible
  }
}

如何在另一个命名空间中声明友元函数?

解决此问题的一种可能方法如下所示:

class A;//forward declaration for class A
namespace helpers{
static void logValue(const A &a); //declaration
}
///////////////////////////////////////////

class A {
    
  friend void helpers::logValue(const A &);

  int _val;
};

namespace helpers {
  static void logValue(const A &a) {
    std::cout << a._val;  // works now
  }
}

上面程序的输出可见here.

要想出解决办法,就要逆向工作。

我们希望它与 _val class Aprivate 成员一起工作。

namespace helpers {
    static void logValue(const A &a) {
       std::cout << a._val;
    }
}

第 1 步 为了使上面的函数定义起作用,必须有一个编译器可见的 class A 的前面定义,并且 class 定义必须指定 helpers::logValue()(具有适当的签名,即 return 类型和参数)是 friend。所以在 helpers::logValue() 上面的定义之前我们必须放置;

class A {
    friend void helpers::logValue(const A &);

    int _val;
};

步骤 2 为了使步骤 1 中的 friend 声明有效,编译器必须知道 helpers::logValue()。这需要命名空间 helpers 的声明区域对编译器可见,编译器声明具有相同签名的函数 logValue(),并且必须在 A 的定义之前。所以,在我们定义 class A 之前,我们必须做一些像;

namespace helpers{
   static void logValue(const A &a);
}

第 3 步 如果 class A 的声明不可见,编译器将在 helpers::logValue() 的这个声明中阻塞。我们已经有一个 class 定义(在第 1 步中创建),因此我们不能再创建一个(这会破坏一个定义规则)。但是我们可以在步骤 2 的代码之前添加一个声明。

class A;

将这些步骤放在一起,我们将这些步骤中的代码以相反的顺序放在一起(即首先放置步骤 3 中的代码,然后是步骤 3 中的代码,依此类推)。然后我们得到

// Step 3
class A;

// Below Step 3 comes code from Step 2

namespace helpers{
   static void logValue(const A &a);    // works since A is declared
}

// Below Step 2 comes code from Step 1

class A {
    friend void helpers::logValue(const A &);   // works since helpers::logValue() is declared

    int _val;
};

//  And now we come to the function definition we want to have work

namespace helpers {
    static void logValue(const A &a) {
       std::cout << a._val;
    }
}