I'd like to use a visitor pattern in combination with smart pointers, but it seems that the compiler can't detect the subclass and match the appropriate function.
I've written an SSCE showing the problem:
test.hpp:
class Visitor;
class Area {
public:
virtual void visit(const Visitor& visitor) = 0;
};
class Area1 : public Area {
public:
virtual void visit(const Visitor& visitor);
};
class Area2 : public Area {
public:
virtual void visit(const Visitor& visitor);
};
class Visitor {
public:
virtual void visit(const Area1 &area) const = 0;
virtual void visit(const Area2 &area) const = 0;
};
test.cpp:
#include "test.hpp"
void Area1::visit(const Visitor& visitor) {
visitor.visit(*this);
}
void Area2::visit(const Visitor& visitor) {
visitor.visit(*this);
}
main.cpp
#include <iostream>
#include "boost/shared_ptr.hpp"
#include "test.hpp"
class FooVisitor : public Visitor {
virtual void visit(const Area1 &area) const {
std::cout <<"visit area1" <<std::endl;
};
virtual void visit(const Area2 &area) const {
std::cout <<"visit area2" <<std::endl;
}
};
int main(int argc, char** argv) {
boost::shared_ptr<Area> p(new Area2);
FooVisitor visitor;
visitor.visit(*p);
return 0;
}
The line visitor.visit(*p) gives this error:
main.cpp: In function ‘int main(int, char**)’:
main.cpp:17:21: error: no matching function for call to ‘FooVisitor::visit(Area&)’
main.cpp:17:21: note: candidates are:
main.cpp:6:18: note: virtual void FooVisitor::visit(const Area1&) const
main.cpp:6:18: note: no known conversion for argument 1 from ‘Area’ to ‘const Area1&’
main.cpp:9:18: note: virtual void FooVisitor::visit(const Area2&) const
main.cpp:9:18: note: no known conversion for argument 1 from ‘Area’ to ‘const Area2&’
How do I help the compiler realize that visit(const Area2&) should be called without resorting to attempting dynamic_cast to each of the subtypes?
This can't work, as the type of *p is indeed Area& (based on the type of the pointer). However, you're using it wrong. To correctly apply the visitor pattern, you should call the visit() defined in Area, to get the correct dispatch:
int main(int argc, char** argv) {
boost::shared_ptr<Area> p(new Area2);
FooVisitor visitor;
p->visit(visitor);
return 0;
}
That's the purpose of the Area::visit() function in the first place.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With