c++lemon-graph-library

Why would candidate '=' operator overload be marked as const?


I can't use std::set_union because I'm not overloading the assignment operator correctly.

I'm using a std::set of my own struct, NodeChange_t, which itself contains another struct, point_t. Here are these guys' operator overloads:

// ---- defs.h
struct point_t
{
    double x;
    double y;

    ...

    void operator=(const point_t &p)
    {
        x = p.x;
        y = p.y;
    }

    ...

};


struct NodeChange_t
{
    SNode node;
    point_t change;
    ListDigraph *graph;

    ...

    void operator=(const NodeChange_t &otherChange)
    {
        this->node = otherChange.node;
        this->change = otherChange.change;
        this->graph = otherChange.graph;
    }

    ...

};

// ---- _2DSurface.cpp

//Problematic code:
void _2DSurface::updateInnerSurfaceV2(_2DSurface &outerSurf, std::set<NodeChange_t> *nodeChanges)
{
    std::set<NodeChange_t> additions;

    ...

    // add stuff to additions
    std::set_union(additions.begin(), additions.end(), nodeChanges->begin(), nodeChanges->end(), nodeChanges->begin());

    ...

}

In this case, I want *nodeChanges to be overwritten. But the error I keep getting is:

src/_2DSurface.cpp:308:7: note: in instantiation of function template specialization
      'std::__1::set_union<std::__1::__tree_const_iterator<ct, std::__1::__tree_node<ct, void *> *, long>,
      std::__1::__tree_const_iterator<ct, std::__1::__tree_node<ct, void *> *, long>, std::__1::__tree_const_iterator<ct,
      std::__1::__tree_node<ct, void *> *, long> >' requested here
        std::set_union(nodeChanges->begin(), nodeChanges->end(), additions.begin(), additions.end(), nodeChanges.begin());
include/defs.hpp:258:7: note: candidate function not viable: 'this' argument has type 'const std::__1::__tree_const_iterator<ct,
      std::__1::__tree_node<ct, void *> *, long>::value_type' (aka 'const ct'), but method is not marked const
        void operator=(struct ct &otherChange)

How does it even make sense that an assignment operator would be marked const, if the whole point is to modify what's on the left hand side? I've been messing around with the const qualifier but can't seem to get anywhere. Any help is appreciated.


Solution

  • How does it even make sense that an assignment operator would be marked const, if the whole point is to modify what's on the left hand side?

    The assignment operator is not marked const. In fact, the error message says as much; it is one of the triggers for the error. Take another look at the relevant parts of the error message with some key emphasis:

    candidate function not viable: 'this' argument has type [snipped] (aka 'const ct'), but method is not marked const

    The other trigger for the error is that the object receiving the assignment is marked const. If you look around the types mentioned in the error message, you might notice "const_iterator". This is your clue! Somewhere a constant iterator is being de-referenced and a value assigned to the result. All iterators involved are set iterators, so let's take a look at documentation for set. A set's iterator type is a constant iterator; you cannot write to it. (For a set, the iterator and const_iterator types are usually aliases for the same type. This redundancy allows an interface that is consistent with other containers.)

    The set_union algorithm requires an output iterator for the destination. A set does not have an output iterator. So even though the word "set" appears in "set_union", set_union cannot directly output a set.

    Also concerning is another detail from the set_union documentation: "The resulting range cannot overlap with either of the input ranges." You cannot accomplish what you want (replace one of the inputs with the union) in one step with set_union. If that is the tool you want to use, you'll need to output the union to an auxiliary container, then update nodeChanges in a separate step. Hoewever, it would probably be simpler to use set::insert (variation 5):

    nodeChanges->insert(additions.begin(), additions.end());