Let's say I start with this simple example of the use of a C++20 "concept":
template <typename T>
concept HasFoo = requires( T t )
{
t.foo();
};
template <HasFoo T>
void DoFoo( T& thing )
{
thing.foo();
}
class FooThing
{
public:
void foo() {}
};
int main(int argc, const char * argv[]) {
FooThing x;
DoFoo( x );
return 0;
}
This compiles, and the concept verifies that the FooThing
class has a method foo
. But suppose I want to make the method foo
private, and call DoFoo
on the FooThing
from
another method of FooThing
. So I try adding a friend declaration:
class FooThing
{
private:
void foo() {}
friend void DoFoo<FooThing>( FooThing& thing );
};
This results in an error message: FooThing
does not satisfy HasFoo
because t.foo()
would be invalid: member access into incomplete type FooThing
.
To reassure myself that the concept really is essential to this problem, I tried doing without it,
template <typename T>
void DoFoo( T& thing )
{
thing.foo();
}
and then the error goes away. Is there any way to fix the error while keeping the concept?
If I try the suggestion of an attempted answer and add a forward declaration
template<typename T> void DoFoo(T&);
before the class, then the compile error goes away, but I get a link error saying that DoFoo(FooThing&)
or DoFoo<FooThing>(FooThing&)
is an undefined symbol.
Yes! This friend declaration compiles and links:
class FooThing
{
//public:
void foo() {}
template<HasFoo T>
friend void DoFoo(T&);
};
I would have to poke around to find the exact standardese, but I know there is a rule that multiple declarations referring to the same template must have the same constraints (typename T
is not allowed here).