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