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 a suggestion of an attempted answer and change my friend declaration to
template <HasFoo T>
friend void DoFoo( FooThing& thing );
then I just get a different error message; instead of complaining that the concept is looking at an incomplete type, it complains that the concept is not satisfied "because t.foo()
would be invalid: foo
is a private member of FooThing
"
If I try the suggestion of a different 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.
CodePudding user response:
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).
CodePudding user response:
The problem is that your concept check requires that T
needs to be a complete type(because of the use of t.foo()
) but at the point of the friend declaration the class FooThing
is incomplete and so the check t.foo()
is invalid. You can confirm this by using some other complete type in the friend declaration and the the concept will work as you intended it to. Demo
Is there any way to fix the error while keeping the concept?
As long as your check requires T
to be a complete type this friend declaration involving FooThing
can't work as at the point of the friend declaration the class in not complete yet.