Как реализовать эквивалент вложенных хэшей Perl в C ++? - PullRequest
5 голосов
/ 30 августа 2010

Я хочу изменить код Perl на C ++.Мне нужно знать, как реализовать вложенные хэши Perl в C ++.Я считал STL хорошим выбором и использовал карты.С помощью карт я могу создать только простой хеш, но я не знаю, как создать вложенную хеш-структуру.

Мой Perl-хэш выглядит так:

%foo = (
    "bar1" => {
        Default => 0,
        Value   => 0
    },
    "bar2" => {
        Default => 2,
        value   => 5,
        other   => 4
    }
)

Я могу изменитьэто так: $foo{"bar1"}->{"Default"} = 15.

Как мне сделать это в C ++ с использованием STL?Может быть, это простой вопрос, но я не могу понять его.

Ответы [ 5 ]

4 голосов
/ 30 августа 2010

Вам может понадобиться тип:

std::map< std::string, std::map<std::string, int> > 

Вместо этого вам может понадобиться struct (или class).

struct Element {
    int default;
    int value;
    int other;
    Element(): default(0), value(0), other(0)
    { }
    Element(int default_, int value_, int other_)
    : default(default_)
    , value(value_)
    , other(other_)
    { }
};

int main() {
    std::map<std::string, Element> elements;
    elements["bar1"]; // Creates element with default constructor
    elements["bar2"] = Element(2,5,4);
    elements["bar3"].default = 5; // Same as "bar1", then sets default to 5
    return 0;
}
2 голосов
/ 30 августа 2010

Как отметил Стив Таунсенд, std::map похожа по своей концепции, но имеет другую реализацию.

Создание вашего вложенного контейнера в C ++ немного более многословно:

#include <tr1/unordered_map>
#include <iostream>

typedef std::tr1::unordered_map< std::string, int >   Inner;
typedef std::tr1::unordered_map< std::string, Inner > Outer;

int main()
{
  Outer foo;

  Inner::value_type bar1_data[] = {
    Inner::value_type("Default", 0),
    Inner::value_type("Value",   0),
  };
  const size_t n_bar1_data = sizeof(bar1_data) / sizeof(*bar1_data);

  foo["bar1"] = Inner(bar1_data, bar1_data + n_bar1_data);

  Inner::value_type bar2_data[] = {
    Inner::value_type("Default", 2),
    Inner::value_type("value",   5),
    Inner::value_type("other",   4),
  };
  const size_t n_bar2_data = sizeof(bar2_data) / sizeof(*bar2_data);

  foo["bar2"] = Inner(bar2_data, bar2_data + n_bar2_data);

Как описанов perlref стрелки между подписывающими скобками являются необязательными, поэтому вы могли бы написать (прокомментировать для поддержки потока программы на C ++)

  // $foo{"bar1"}{"Default"} = 15;

, что довольно близко к C ++:

  foo["bar1"]["Default"] = 15;

Для правильности измерения мы печатаем полученную структуру и возвращаем 0 из main:

  for (Outer::const_iterator o = foo.begin(); o != foo.end(); ++o) {
    std::cout << o->first << ":\n";
    for (Inner::const_iterator i = o->second.begin(); i != o->second.end(); ++i)
      std::cout << "  - " << i->first << " => " << i->second << '\n';
  }

  return 0;
}

Вывод:

bar1:
  - Value => 0
  - Default => 15
bar2:
  - Default => 2
  - value => 5
  - other => 4

ПРИМЕЧАНИЕ: В этой игрушечной программе порядок ввода и вывода одинаков, но не зависит от этого поведения!

Если вместо этого вы предпочитаете использовать boost::unordered_map, измените несколько строк вверх вашей программы:

#include <boost/unordered_map.hpp>

typedef boost::unordered_map< std::string, int >   Inner;
typedef boost::unordered_map< std::string, Inner > Outer;
2 голосов
/ 30 августа 2010

Вы можете иметь вложенные хэши с std::map<key_t,std::map<key_t,value_t> >.

0 голосов
/ 31 августа 2010

Как мне сделать это в C ++ с использованием STL?Может быть, это простой вопрос, но я не могу понять его.

То, как вы используете хэш Perl, является обычным способом имитировать C / C ++ struct.

Таким образом, я думаю, что ближайший C ++ перевод вашего кода:

struct foobar {
   int Default, value, other;

   foobar(int Default_ = 0, int value_ = 0, int other_ = 0)
     : Default(Default_), value(value_), other(other_)
   {}
};

std::map< std::string, foobar > foo;

foo["bar1"] = foobar( 0, 0 );
foo["bar2"] = foobar( 2, 5, 4 );
0 голосов
/ 31 августа 2010

Позвольте мне добавить мета-информацию к вопросу.Другие предоставили реальные образцы рабочего кода.

Помимо того, что это другой тип контейнера (O (log (n) доступ для карт C ++ и обычно O (1) для хэшей Perl), главное отличие между C ++Хэши map и Perl заключаются в различии статических и динамических типов самих языков. Аргументы шаблона карты четко указывают тип ключа и значения, тогда как для хэшей Perl только ключ имеет известный тип (строку). Значениеявляется скаляром, но он может и обычно содержит какую-либо структуру данных. Таким образом, очень сложно использовать карты C ++ для довольно обычной структуры данных Perl, такой как:

{
  foo => [qw(bar baz)],
  quibble => {
    lion => 'animal',
    pine => 'plant',
  },
  count => 5,
}

Это болеепрактического различия, чем концептуального, потому что вы всегда можете определить структуру / класс / тип, который будет содержать произвольный материал (см. другие ответы). Это просто намного больше работы и в итоге становится довольно громоздким в использовании.

Использование простого шаблонного типа, такого как map<string, map<string, Stuff> >, действительно возможно только в том случае, если структура вашегоА очень регулярно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...