1

I tried to insert a Movie object to the unordered_set<Movie> container, but I got an error saying that there is no such a matching member function. I did something like this

void ActorGraph::addActor(string actor_name, string movie_title, int movie_year){
    unordered_map<string, unordered_set<ActorNode>>::iterator con_itr = connections.find(actor_name);
    ActorNode actor(actor_name);
    Movie movie(movie_title, movie_year);

    if(con_itr != connections.end()){
        auto adjSet = con_itr->second;
        unordered_set<ActorNode>::iterator act_itr = adjSet.find(actor);
        if(act_itr != adjSet.end()){
            //in the set
            auto mov_itr = act_itr->movies.find(movie);
            if( mov_itr == act_itr->movies.end()){
                act_itr->movies.insert(movie) //no matching function, while act_itr->movies is of type unordered_set<Movie>
            }
        }
    }else{
        unordered_set<ActorNode> adjSet;
        actor.movies.insert(movie);
        adjSet.insert(actor);
        connections[actor_name] = adjSet;
        cout << "The size is: " << actor.movies.size() << endl;
    }
}

My ActorNode is a struct which looks like this

struct ActorNode{
    //the name of the actor/actress
    string name;

    /** the movie that this actor/actree participated in
     */
    unordered_set<Movie> movies;

    ActorNode(string n) : name(n){}

    bool operator ==(const ActorNode &other) const;
};


namespace std
{
    template <>
    struct hash<ActorNode>
    {
        size_t operator()(const ActorNode& actor) const
        {
            return hash<std::string>{}(actor.name);
        }
    };
}

Movie struct

#ifndef Movie_h
#define Movie_h

#include <iostream>
using namespace std;

struct Movie{
    string name;
    int year;
    Movie(string n, int y): name(n), year(y){}
    bool operator ==(const Movie &m) const;
};



namespace std
{
    template <>
    struct hash<Movie>
    {
        size_t operator()(const Movie& movie) const
        {
            return hash<std::string>{}(movie.name + to_string(movie.year));
        }
    };
}


#endif /* Movie_ph*/

enter image description here

I have implemented and overrode the operator and make both my Movie and ActorNode struct compatible for using in the key of unordered_set

Here is the repository: Repo


Minimal Reproduction Example

#include <iostream>
#include <string>
#include <unordered_set>

struct Movie{
    std::string name;
    int year;

    Movie(std::string n, int y): name(std::move(n)), year(y)
    {
    }

    bool operator ==(const Movie &m) const
    {
        return year == m.year && name == m.name;
    };
};


namespace std
{
    template <>
    struct hash<Movie>
    {
        size_t operator()(const Movie& movie) const
        {
            return hash<std::string>{}(movie.name + to_string(movie.year));
        }
    };
}
////////////////////

struct ActorNode
{
    std::string name;
    std::unordered_set<Movie> movies;

    ActorNode(std::string n) : name(std::move(n))
    {
    }

    bool operator ==(const ActorNode &other) const
    {
        return name == other.name;
    }
};


namespace std
{
    template <>
    struct hash<ActorNode>
    {
        size_t operator()(const ActorNode& actor) const
        {
            return hash<std::string>{}(actor.name);
        }
    };
}
////////////////////


int main()
{
    std::unordered_set<ActorNode> actors;
    actors.emplace("Gene Wilder");

    auto itr = actors.find(ActorNode("Gene Wilder"));
    if (itr != actors.end())
    {
        // error: no matching function for call to                  
        //  'std::unordered_set<Movie>::insert(Movie) const'
        itr->movies.insert(Movie("Stir Crazy", 1980)); 
    }
}
WhozCraig
  • 65,258
  • 11
  • 75
  • 141
Kesong Xie
  • 1,316
  • 3
  • 15
  • 35

1 Answers1

2

Problem is that you cannot modify key of set, cause it can lead to set rebuild, but set will not be rebuilded, cause you just modify variable, nothing else. So, it is explicitly forbidden.

Definition of iterator in unordered_set

iterator    Constant ForwardIterator
const_iterator  Constant forward iterator
ForEveR
  • 55,233
  • 2
  • 119
  • 133
  • 1
    I have no idea why I didn't remember this. If I remember right, set iterators (both ordered and otherwise) were made `const` to prevent this very problem (people modifying set containment) in C++11 (it's late here and I'm tired, but I *think* that was when it took hold). – WhozCraig Feb 28 '17 at 09:25
  • Good to know about this, thanks, I may try to find some work around – Kesong Xie Feb 28 '17 at 09:26
  • @KesongXie use a map (ordered or not) instead, mapping the only thing you probably care about (the names) to the related objects. The mapped-to-value is freely modifiable in that case. Worth considering. – WhozCraig Feb 28 '17 at 09:27
  • Yes, I might go for an unordered_map, thanks @WhozCraig – Kesong Xie Feb 28 '17 at 09:29
  • @WhozCraig ye, that is true. – ForEveR Feb 28 '17 at 09:30
  • 1
    @KesongXie high-hit question for more info in case you're interested [can be found here](https://stackoverflow.com/questions/2217878/c-stl-set-update-is-tedious-i-cant-change-an-element-in-place). – WhozCraig Feb 28 '17 at 09:31