2

I am trying to code Conway's "Game of Life". While getting closer to my goal I got stuck with a compiler error:

C2338: The C++ Library doesen't provide a hash for this type.

At first I used the SFML class sf::Vector2D. When it failed to work for me I wrote a class of my own, hoping I could implement the missing hashCode method.

My question is:
Is it possible to uses my own class with its own hashCode method for std::unordered_map? I need to use a class, that can hold two numbers. (I also tried std::tuple, struct and stuff).

Here is one sheet of my code:

#include "GameMechanics.h"



GameMechanics::GameMechanics(Elements * elements):elements(elements)
{
    this->refreshTime = 1000000;    //ms
    this->clock.restart();
}


GameMechanics::~GameMechanics()
{
}

bool GameMechanics::isRunning()
{
    return this->running;
}

void GameMechanics::setRunning(bool running)
{
    this->running = running;
}

void GameMechanics::loop()
{

    unsigned passedTime = clock.getElapsedTime().asMicroseconds();  //check passed time since the clock got restarted
    this->timeHeap  +=  passedTime; //add passed time to the timeheap
    this->clock.restart();
    //only refresh every "refreshTime" seconds
    if (timeHeap >= this->refreshTime) {    
        std::cout << "Calculated new generation!" << std::endl;
        this->timeHeap -= this->refreshTime;
        this->calculateNextGeneration();
    }
}

void GameMechanics::calculateNextGeneration()
{
    std::list<sf::Vector2i> oldGeneration = this->elements->getElements();  //  population in the moment

    sf::Vector2u elements = this->elements->getElementCount();

    std::unordered_map<MyVector2D, int> counter;     //here is the problem. Thats the line that makes some trouble


    for (std::list<sf::Vector2i>::iterator it = oldGeneration.begin(); it != oldGeneration.end(); it++) {
        sf::Vector2i position = *it;

        for (int i = -1; i < 2; i++) 
        {
            for (int j = -1; j < 2; j++) 
            {
                if (position.x + i >= 0 && position.x + i <= this->elements->getElementCount().x &&
                    position.y + j >= 0 && position.y + j <= this->elements->getElementCount().y) 
                {
                    if (counter.find(MyVector2D(position.x + i, position.y + j)) != counter.end()) 
                    {
                        counter.at(MyVector2D(position.x + i, position.y + j))++;
                    }
                    else //if there is no such element, create a new entry
                    {
                        counter.insert({ MyVector2D(position.x + i, position.y + j),1 });
                    }
                }
            }
        }
    }


    //create new generation
    this->brithNewGeneration(&counter);
}

void GameMechanics::brithNewGeneration(std::unordered_map<MyVector2D,int>* counter)
{
    //this methode does work

    std::list<sf::Vector2i> newGeneration;
//  for (std::unordered_map<MyVector2D, int>::iterator it = counter->begin(); it != counter->end(); it++) 
    {
        //if life vell with < 2 neighbours, it dies
        //life cell with 2 or 3 neighbours will continue living

        //life cell with >4 cells will die

        //dead cell with 3 neighbours will start living
    }
}
1
  • Unrelated: unless you are inserting elements in the middle of the sequence all the time, std::list is almost never a good container choice. Commented May 14, 2017 at 13:03

1 Answer 1

6

The custom hashing function required for std::unordered_map (and std::unordered_set) is not a member function of the stored type. You need to specialize the std::hash template:

namespace std {
    template<>
    struct hash<YourType> {
        using argument_type = YourType;
        using result_type = std::size_t;

        result_type operator()(argument_type const &obj) const {
            // Compute and return the hash value for `obj`.
        }
    };
}

Your case is precisely the reason why it's done this way: you can specialize std::hash for sf::Vector2D if you wish, no need to implement your own class.

Sign up to request clarification or add additional context in comments.

1 Comment

Related: stackoverflow.com/a/38140932/214671; in this specific case, my MAKE_HASHABLE macro would reduce the whole solution to MAKE_HASHABLE(sf::Vector2i, t.x, t.y).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.