简体   繁体   中英

How can I fix a C++20 compile error involving concepts and friends?

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).

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 concept 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM