Tenho as seguintes classes CRTP que desejo usar para implementar um padrão Visitor
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));
}
};
Então eu defino uma classe visitável
class Data : public Visitable<Data>
{
private:
std::string foo;
};
e um visitante para a classe
class Printer : public Visitor<Data>
{
void visit(Data& data)
{
std::cout << data.foo << std::endl;
};
};
Mas o compilador me diz que "foo é um membro privado de 'Data'"... por que minha especificação de amigo não funciona como esperado?
Também tentei mover o "amigo" para a classe derivada, mas isso não resolveu o problema.
class Data : public Visitable<Data>
{
friend void Visitor<Data>::visit(Data&); // instead of in Visitable
private:
std::string foo;
};