0

I have a program structured similiar to:

class A {
    private:
        std::set<B> members;
    public:
        void func(const C& arg) {
            std::set<B>::iterator iter = members.find(a);
            if(iter != members.end()) {
                iter->check(arg);
            }
        }
}



class B {
    private:
        std::deque<C> writers;
    public:
        void check(const C& arg) {
            if(std::find(writers.begin(), writers.end, arg) != writers.end()) {
                /* Code */
            }
        }
}


class C {
  private:
      int id;
  public:
      bool operator==(const C& arg) {
          return arg.id == this->id;
      }
}

When I compile this, I get the following error message:

no matching function for call to ‘B::check(const C&) const’  
note: candidates are: void B::check(const C&) <near match>

If I declare check() as const then the compiler throws an error demanding that the overloaded operator == in Class C to be declared as const. I don't know if making the overloaded operator as const is the right thing to do. (I tried it once and as far as I can recollect it also gave some error).

I been trying to solve this for more than five days and still no leads.

WeaklyTyped
  • 1,331
  • 4
  • 16
  • 31
  • 3
    Well, making operator== const may have introduced some extraneous error, but it's the right thing to do. Equality tests should not modify the objects that they are applied to. So make it const, and deal with whatever other issues you run into. – Pete Becker Sep 27 '12 at 15:53
  • I _think_ `set::iterator` types are `const` as if not it would be possible to modify the `key` of the container, possibly breaking the ordering. So `iter->check(arg)` is being called on a `const B` instance but `check()` is not-`const` hence the error. – hmjd Sep 27 '12 at 16:00

3 Answers3

3

The first thing is that operator== should be const. It does not modify data, nor should it ever unless you want to confuse your users. In general every function that need not modify the state of the object should be const as to provide the maximal flexibility (i.e. allow calls through constant references).

The same can be applied to B::check, if it does only test and not modify, then it should be const. And by extension in A::func, if it does not need to modify then it should be const.

The error message will be slightly different in different compilers. In your case the compiler performed overload resolution and did not find a match to the call which is what it complains about:

no matching function for call to ‘B::check(const C&) const’
note: candidates are: void B::check(const C&)

Which indicates that it saw your member but discarded it as it needed a member function with the const tag. In other compilers the error message will contain something on the lines of: calling void B::check(const C&) discards qualifiers which is a bit more convoluted and tries to say that calling a non-const member function on a const reference would require ignoring the const qualifier.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • It might be good to explain why he's getting the error as well. – Seth Carnegie Sep 27 '12 at 15:56
  • This one helped; indeed when I declared a cascading `const` as required, the original problem was solved and the new errors though related to the same function were not because of `const` declaration. Thanks! – WeaklyTyped Sep 27 '12 at 16:23
3

You definitely shall declare B::check() and C::operator== as const as they don't change anything in object state.

Also it may be not so obvious, but std::set<B>::iterator is actually const_iterator (suppose you are using C++11 compiler)! So you are unable to call any non-const function members from B objects via set iterator.

Rost
  • 8,779
  • 28
  • 50
  • Is that bit about `iterator` being `const_iterator` in C++11 really true? It doesn't make sense, as you should be able to make any modification to the member that you want as long as it doesn't affect its strict ordering. Imagine a set of complex objects that contain only a single member as the key. – Mark Ransom Sep 27 '12 at 17:14
  • @MarkRansom Yes, it's true, see the link in answer. It states that iterator is const iterator since C++11. Well, actually it makes sense because it guarantees that container data ordering will not be ruined. To effectively modify object in set with no impact on key you could use combination of `erase` and `insert` with iterator hint, in this case insertion will be constant time. – Rost Sep 27 '12 at 17:24
  • I hate it when the standard makes breaking changes like that. – Mark Ransom Sep 27 '12 at 18:39
  • @MarkRansom Modifying iterators referring to elements of the set was undefined behavior anyways. –  Sep 28 '12 at 09:37
-1

Remember that when it is possible you should prefer non-const version. At least this is what scott mayber said.

Here is a long discussion:

Should I prefer iterators over const_iterators?

Community
  • 1
  • 1
CyberGuy
  • 2,783
  • 1
  • 21
  • 31