Как создать хэш хэшей в C++?

Есть ли способ создать хэш хэшей на С++?

По сути, я пытаюсь сделать то, что вы можете сделать на Perl, но только на C++. Вот пример кода Perl, который я хотел бы сделать на C++.

%hash = (
gameobject1 => {
    position => {
        x_loc => 43,
        y_loc => 59,
    }
    rect_size => {
        width => 5,
        height => 3,
    }
    collidable => 1,
    sounds => {
        attack => "player_attack.ogg",
        jump => "player_jump1.ogg",
        jump_random => [qw/player_jump1.ogg player_jump2.ogg player_jump3.ogg/]
    }

},
gameobject2 => {
    position => {
        x_loc => 24,
        y_loc => 72,
    }
    rect_size => {
        width => 2,
        height => 4,
    }
    sounds => {
        attack => "goblin_attack.ogg",
    }
        items => [qw/sword helmet boots/]
},
);

Следует отметить, что хеши с игровыми объектами могут существовать или нет... т. е. позиция может существовать в игровом объекте1, но может не существовать для игрового объекта35.

Любые идеи?


person vternal3    schedule 10.01.2012    source источник
comment
Я заменил c/c++ в вашем вопросе только на C++, потому что C и C++ — разные языки. Пожалуйста, поправьте меня, если мое предположение было неверным, и вы действительно заинтересованы в решении C.   -  person R. Martinho Fernandes    schedule 10.01.2012
comment
Я как бы шел либо к тому, либо к тому, что когда-либо имело смысл :) С++ работает   -  person vternal3    schedule 10.01.2012


Ответы (3)


Хеши Perl позволяют вам использовать что угодно в качестве значений. C++, будучи статически типизированным языком, не позволит вам сделать это: вам нужно точно указать, какой тип вы хотите, чтобы значения в хэше (на жаргоне C++, карта) имели.

Вот возможное решение с С++ 11 и boost, с добавлением строгой типизации :)

#include <map>
#include <vector>
#include <string>
#include <boost/optional.hpp>

// Coordinates are always like this, aren't they?
struct coords {
    int x_loc;
    int y_loc;
};

// Dimensions are always like this, aren't they?
struct dims {
    int width;
    int height;
};

// Sound maps: each string key maps to a vector of filenames
typedef std::map<std::string, std::vector<std::string>> sound_map;
// Item lists: looks like it's just a collection of strings
typedef std::vector<std::string> item_list;

// Fancy names to improve readability
enum collidability : bool {
    collidable = true,
    not_collidable = false
};

// A structure to describe a game object
struct game_object {
    // An optional position
    boost::optional<coords> position;
    // An optional rectangle size
    boost::optional<dims> rect_size;
    // Assuming "false" can mean the same as "no collidable key"
    bool collidable;
    // Assuming an "empty map" can mean the same as "no map"
    sound_map sounds;
    // Assuming an "empty vector" can mean the same as "no vector"
    item_list items;
    // If any of the above assumptions is wrong,
    // sprinkle boost::optional liberally :)
};

// Finally, values for our "hash"
std::map<std::string, game_object> hash {
    { "game_object1",
      {
        coords { 43, 59 },
        dims { 5, 3 },
        collidable, // remember those fancy names?
        sound_map {
             { "attack", { "player_attack.ogg" } },
             { "jump", { "player_attack.ogg" } },
             { "jump_random", { "player_jump1.ogg", "player_jump2.ogg", "player_jump3.ogg" } }
        },
        item_list {}
    } },
    { "game_object2",
      {
        coords { 24, 72 },
        dims { 2, 4 },
        not_collidable,
        sound_map {
             { "attack", { "goblin_attack.ogg" } }
        },
        item_list { "sword", "helmet", "boots" }
    } },
    { "game_object25",
      {
        boost::none, // no position
        dims { 2, 4 },
        not_collidable,
        sound_map {
             { "attack", { "goblin_attack.ogg" } }
        },
        item_list { "sword", "helmet", "boots" }
    } }
};

Если вам действительно нужно что-то вроде хеша Perl из хэшей Perl, вы можете использовать std::map<std::string, boost::any>, чтобы получить возможность хранить что-либо на карте. Однако это требует, чтобы вы проверили типы каждого значения, прежде чем получать его из карты. Если возможен только определенный набор типов, вы можете использовать что-то более строго типизированное, чем boost::any, например boost::variant.

person R. Martinho Fernandes    schedule 10.01.2012
comment
Вы пытались это скомпилировать? Я получаю сообщения об ошибках hash {: error C2470: 'hash': похоже на определение функции, но списка параметров нет; пропуская видимое тело, а также в dims { 2, 4 }, и sound_map { { "attack", { "player_attack.ogg" } }, - person vternal3; 10.01.2012
comment
@vternal3: да, это отлично компилируется в GCC 4.7. Как я уже упоминал в ответе, здесь используются функции С++ 11, поэтому для этого вам нужен довольно свежий компилятор. - person R. Martinho Fernandes; 10.01.2012

Использовать std::map?

Что-то типа:

#include <map>
#include <string>
class GameObject;
typedef std::map<std::string, GameObject> object_map_t;
typedef std::map<std::string, object_map_t> map_of_object_maps_t;
person Naddiseo    schedule 10.01.2012
comment
Это хороший дословный перевод, но он может иметь очень плохую производительность. Я бы рассмотрел некоторое представительство, если это возможно. - person André Caron; 10.01.2012
comment
Его вопрос заключался в том, как создать хэш из хэшей. Но я согласен, лучше использовать классы со свойствами. - person Naddiseo; 10.01.2012

Этот пример может помочь вам понять реализацию:

#include <map>
#include <string>
#include <iostream>
using namespace std;

void main() {

    map<string, map<string, int>> hash;
    hash["A"]["A"] = 1;
    hash["A"]["B"] = 2;
    hash["B"]["A"] = 4;
    hash["B"]["B"] = 8;

    for(map<string, int>::iterator i = hash["B"].begin(); i != hash["B+"].end(); i++) {
        cout << i->first << " - " << i->second << "\n";
    }
}

Ваше здоровье...:)

person Vinay Jain    schedule 10.01.2012