c++templatesfriendcrtp

C++ Template Class friend in CRTP pattern


I have the following CRTP classes which i want to use to implement a Visitor pattern

template <class Derived>
class Visitor
{
public:
    Visitor() {
        static_assert(!std::is_same<Visitor, Derived>::value,
                      "Visitor class cannot be instantiated directly. Use a derived class.");
    }
    virtual ~Visitor() = default;
    virtual void visit(Derived&) = 0;
};

template <class Derived>
class Visitable
{
friend void Visitor<Derived>::visit(Derived&);

public:
    Visitable() {
        static_assert(!std::is_same<Visitable, Derived>::value,
                      "Visitable class cannot be instantiated directly. Use a derived class.");
    }

    template <class T>
    void accept(T& visitor)
    {
        visitor.visit(static_cast<Derived &>(*this));
    }
};

Then I define a visitable class

class Data : public Visitable<Data>
{
    private:
        std::string foo;
};

and a visitor for the class

class Printer : public Visitor<Data>
{
    void visit(Data& data)
    {
        std::cout << data.foo << std::endl;
    };
};

But the compiler tells me that "foo is a private member of 'Data'"... why does my friend specification not work as intended?

I also tried moving the "friend" to the derived class but it did not solve the issue.

class Data : public Visitable<Data>
{
    friend void Visitor<Data>::visit(Data&); // instead of in Visitable
    private:
        std::string foo;
};

Solution

  • friendship is not inherited.

    You have to add friend Printer; in class Data

    class Data : public Visitable<Data>
    {
        friend Printer;
    private:
        std::string foo;
    };