0

I have a scene class for objects, cameras, and lights in my game

class Scene {
    private:
        std::vector<GameObject> objects;
        std::vector<Light> lights;
        // ... more containers ...

and I am trying to create a class interface that lets the user add, remove, retrieve, and iterate through these objects without giving them specific access to the underlying container (a vector at this point).

    public:
        GameObject& get_game_object(const unsigned int id);
        void add_game_object(const GameObject& object);
        void remove_game_object(const unsigned int id);

Adding, removing, and retrieving objects within the scene works fine.


I encounter a problem though, when attempting to iterate through these game objects.

    template<class T>
    void for_each_game_object(T t) const {
        std::for_each(begin(objects), end(objects), t);
    }

This "wrapper" works fine for my underlying class of vectors.

scene.for_each_game_object([] (GameObject& object) {
    // do something in the lambda
});

But now I want to swap out my vectors for unordered_maps where the key is an unsigned integer, and the value is the GameObject (or Camera or Light or etc.).

The for_each_game_object loop now requires a different lambda, and exposes the key/value pair to the end-user. Is there any way to rewrite the for_each_game_object loop to only iterate over the values of the map and ignore the ids (which are used internally by the Scene class)?

sdasdadas
  • 23,917
  • 20
  • 63
  • 148
  • Not sure if this answers your question: http://stackoverflow.com/questions/259240/iterator-adapter-to-iterate-just-the-values-in-a-map – happydave Jul 11 '16 at 00:27
  • If you want to iterate, an `unordered_map` is likely not the right choice. Why do you think you want an `unordered_map`? – Lightness Races in Orbit Jul 11 '16 at 00:28
  • 2
    trampoline? `std::for_each(begin(objects), end(objects), [](auto el) { t(el.second); });` – kfsone Jul 11 '16 at 00:31
  • @LightnessRacesinOrbit I'm not too sure since this is a bit new to me. I assume I'll be looking up objects on some components (id, coordinates, etc.) and I thought linear look-ups might be a bad choice. It might just be theoretical though. – sdasdadas Jul 11 '16 at 00:35
  • @kfsone I think this has worked, thanks. The only two changes are to capture the `t` variable in `[]` and you can't use `auto` inside a lambda, afaik. – sdasdadas Jul 11 '16 at 00:35
  • 1
    @sdasdadas Ah, you can in C++14 (`The list of parameters, as in named functions, except that default arguments are not allowed (until C++14). If auto is used as a type of a parameter, the lambda is a generic lambda. (since C++14)` – kfsone Jul 11 '16 at 00:37
  • There are more options than just `std::vector` and `std::unordered_map`. Think carefully about your container choice. – Lightness Races in Orbit Jul 11 '16 at 08:51

2 Answers2

1

For the technical problem: pass a functor (e.g. a lambda) that invokes the client code's functor.

But do note that with a vector, if removing an object at a given index shifts the indices (id's) of the following objects, then the behavior with a map is different. So this change can break your existing client code. I.e. the problem can be more than just the technical one of adapting a lambda.

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
1

This code maps a function over just the value part of a map's key/value pair:

class Wrapper
{
public:
    void Apply(const std::function <void (const std::string)>& functor)
    {
        for (auto i : _Map)
        {
            functor(i.second);
        }
    }
private:
    std::unordered_map<int, std::string>    _Map;
};