Is it possible to declare a friend function as static?
Sure. Read the second line of the error message carefully: the function was declared extern
and later static
. So all you have to do is declare it static before the friend declaration:
class A;
static void IncrementValue(A&);
class A {
// class definition, including friend declaration
};
static void IncrementValue(A&) {
// code here, of course
}
Quoting N3691 - §11.3/4 [class.friend]
A function first declared in a friend declaration has external linkage (3.5). Otherwise, the function retains its previous linkage (7.1.1).
So you need to declare the function as static
prior to declaring it as a friend
. This can be done by adding the following declarations above the definition of A
.
class A; // forward declaration, required for following declaration
static void IncrementValue(A&); // the friend declaration will retain static linkage
While Praetorian's answer is technically correct in that it answers the question you explicitly asked, I believe it is not a useful answer in that what he proposes is both unsound and it also does not fulfill your stated objective of wishing to define a method that can be called in the friend classes' translation unit only.
There are two problems with his solution. Firstly any other translation unit that includes the header containing the class definition preceeded by the static function declaration will fail to compile due to the error that the statically declared friend function is not defined in the referencing translation module. And secondly, the referencing translation unit can eliminate that compile error by defining the statically declared function itself, and that definition will be able to access all the private data of the class that the function was declared a friend of. This suggests that friend functions should always be left having the public linkage that is their default, as this prevents this potential encapsulation breach due to multiple definitions of a public linkage function being a compile error.
I believe @engf was on the right track in his comment on your question, you need a friend class defined in the same translation unit as the class you wish it to be able to access. E.g.
// A.h
class A
{
public:
A() : _value(0) {}
private:
int _value;
friend struct A_Accessor;
};
// A.cpp
struct A_Accessor
{
static void IncrementValue(A& a)
{
++a._value;
}
};
TEST(StaticInit, IncrementA)
{
A a;
A_Accessor::IncrementValue(a);
}
This will define IncrementValue in a way that permits it to access A's private data, yet cannot be referenced from outside A's translation module.