1

I have a ShapeType, Point, with some coordinates, (1,2), and I'd like to use apply_visitor in an overloaded operator () to add the coordinates (3,4) to my Point, so that Point ends up being (4,6). Where is my implementation failing? I think my ShapeVisitor class is correct, but I am getting an error, "apply_visitor" is not a member of CLARK::Point.

Code is as follows.

#include "Point_H.hpp"
#include "Shape_H.hpp"
#include "boost/variant.hpp"

typedef boost::variant<Point,Line,Circle> ShapeType;

ShapeType ShapeVariant(){...}

class ShapeVisitor : public boost::static_visitor<> 
{
private:
    double m_dx; // point x coord
    double m_dy; // point y coord

public:    
    ShapeVisitor(double m_dx, double m_dy);
    ~ShapeVisitor();

    // visit a point
    void operator () (Point& p) const
    {
        p.X(p.X() + m_dx);
        p.Y(p.Y() + m_dy);
    }
};

int main()
{   
    using boost::variant;

    ShapeType myShape = ShapeVariant(); // select a Point shape

    Point myPoint(1,2);

    boost::get<Point>(myShape) = myPoint; // assign the point to myShape

    boost::apply_visitor(ShapeVisitor(3,4), myPoint); // trying to add (3,4) to myShape

    cout << myPoint << endl;

    return 0;
}

Thanks!

ch-pub
  • 1,664
  • 6
  • 29
  • 52

1 Answers1

3
  1. You are missing the include (Edit: doesn't seem to be required anymore)

    #include "boost/variant/static_visitor.hpp"
    
  2. Also instead of

    boost::get<Point>(myShape) = myPoint;
    

    You'll just want to do

    myShape = myPoint;
    

    Otherwise, if the variant did not actually contain a Point yet, you'll receive a boost::bad_get exception

  3. Finally

    boost::apply_visitor(ShapeVisitor(3,4), myPoint);
    

    should have been

    boost::apply_visitor(ShapeVisitor(3,4), myShape);
    

A simple self-contained example that shows all these points would look like this: (See it live on http://liveworkspace.org/code/33322decb5e6aa2448ad0359c3905e9d)

#include "boost/variant.hpp"
#include "boost/variant/static_visitor.hpp"

struct Point { int X,Y; };

typedef boost::variant<int,Point> ShapeType;

class ShapeVisitor : public boost::static_visitor<> 
{
private:
    double m_dx; // point x coord
    double m_dy; // point y coord

public:    
    ShapeVisitor(double m_dx, double m_dy) : m_dx(m_dx), m_dy(m_dy) { }

    void operator () (int& p) const { }

    // visit a point
    void operator () (Point& p) const
    {
        p.X += m_dx;
        p.Y += m_dy;
    }
};

int main()
{   
    Point myPoint{ 1,2 };

    ShapeType myShape(myPoint);
    boost::apply_visitor(ShapeVisitor(3,4), myShape);

    myPoint = boost::get<Point>(myShape);
    std::cout << myPoint.X << ", " << myPoint.Y << std::endl;
}

Output:

4, 6
sehe
  • 374,641
  • 47
  • 450
  • 633
  • Indeed, including "boost/variant/static_visitor.hpp" does not change the functionality. This is a significant change, though: `boost::apply_visitor(ShapeVisitor(3,4), myShape);` Now I get an error, "error C2664: 'void ShapeVisitor::operator ()(CLARK::Point &) const' : cannot convert parameter 1 from 'T1' to 'CLARK::Point &'" Is it a problem with the ShapeVisitor members? – ch-pub Oct 07 '12 at 00:03
  • 1
    @Clark likely, yes. In my sample, note that the `operator()(int&) const` overload is _required_ for the visitor to compile. In short, you need an overload that matches _every_ type in the variant. You'll find out why the use of `boost::get` was also critically wrong when you _run_ the compiled code :) – sehe Oct 07 '12 at 00:04
  • My problem was that I didn't yet have an overload that matched every type in the variant. Now I've created them (empty, like your overloaded operator for int), and I'm running into dreaded LNK errors! "Test.obj : error LNK2019: unresolved external symbol "public: __thiscall ShapeVisitor::~ShapeVisitor(void)" (??1ShapeVisitor@@QAE@XZ) referenced in function _main" and "Test.obj : error LNK2019: unresolved external symbol "public: __thiscall ShapeVisitor::ShapeVisitor(double,double)" (??0ShapeVisitor@@QAE@NN@Z) referenced in function _main". These have always been tough for me to figure out. – ch-pub Oct 07 '12 at 00:13
  • @Clark see my sample again: you need to implement the functions you declare in ShapeVisitor. If you do, refer to [what-is-an-undefined-reference-unresolved-external-symbol-error-and-how-do-i-fix](http://stackoverflow.com/questions/12573816/) for help in finding the solution there. It is really not that complicated. You'll get it soon enough :) – sehe Oct 07 '12 at 00:18
  • That's what I meant. In particular, I added this: "void operator () (Line& lp) const { }" and this "void operator () (Circle& cp) const { }". Those are my only other ShapeTypes. That got me a lot further, but I ran into this new linker error. I'm checking the thread you provided right now. – ch-pub Oct 07 '12 at 00:21
  • @Clark I meant, you are missing the _definition_ (body) for the ShapeVisitor constructor/destructor (at least during the linking step). This is what the linker error refer to. And the linked answer explains more in depth – sehe Oct 07 '12 at 00:28