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

Ale*_*der 1 c++ friend-function

/** 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
  }
}
Run Code Online (Sandbox Code Playgroud)

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

Pet*_*ter 5

要想找到解决办法,就必须逆向思考。

我们希望它能与班级成员_val一起使用。privateA

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

步骤 1 要使上面的函数定义起作用,必须有A编译器可见的类的前面定义,并且该类定义必须指定helpers::logValue()(具有适当的签名,即返回类型和参数)是friend. 所以在上面的定义之前helpers::logValue()我们必须放置;

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

    int _val;
};
Run Code Online (Sandbox Code Playgroud)

步骤 2为了使friend步骤 1 中的声明有效,编译器必须了解helpers::logValue(). 这需要编译器可见的命名空间声明区域,该区域声明具有相同签名的helpers函数,并且必须位于 的定义之前。因此,在定义 class 之前,我们必须做类似的事情;logValue()AA

namespace helpers{
   static void logValue(const A &a);
}
Run Code Online (Sandbox Code Playgroud)

步骤 3helpers::logValue()如果没有可见类的声明, 编译器将因该声明而阻塞A。我们已经有了一个类定义(在步骤 1 中创建),因此我们无法创建另一个类定义(这会打破单一定义规则)。但是我们可以在步骤 2 中的代码之前添加一个声明。

class A;
Run Code Online (Sandbox Code Playgroud)

将这些步骤放在一起,我们将步骤中的代码以相反的顺序放在一起(即首先放置步骤 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;
    }
}
Run Code Online (Sandbox Code Playgroud)