операторы индекса для класса с переменной члена std :: map - PullRequest
2 голосов
/ 20 февраля 2012

Я пытаюсь создать класс, который упаковывает std :: map и выполняет проверку, чтобы убедиться, что ключи являются одной из утвержденных допустимых строк, а также инициализирует карту, чтобы иметь значения по умолчанию для всех утвержденных допустимых строк. У меня возникли проблемы с работой оператора индекса, в частности его константной версии.

Вот мой код прототипирования класса:

#include <set>
#include <string>
#include <map>

class foo {
  public:
    foo() {}
    const double & operator[](const std::string key) const {
      return data[key];
    }
  private:
    static const std::set<std::string> validkeys;
    std::map<std::string, double> data;
};

const std::set<std::string> foo::validkeys = {"foo1", "foo2"};

Когда я компилирую это (используя g ++ с -std = c ++ 0x), я получаю эту ошибку компиляции:

|| /home/luke/tmp/testmap.cc: In member function 'double& foo::operator[](std::string) const':
testmap.cc|10 col 22 error| passing 'const std::map<std::basic_string<char>, double>' as
'this' argument of 'mapped_type& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const
key_type&) [with _Key = std::basic_string<char>, _Tp = double, _Compare =
std::less<std::basic_string<char> >, _Alloc = std::allocator<std::pair<const 
std::basic_string<char>, double> >, mapped_type = double, key_type = 
std::basic_string<char>]' discards qualifiers

Ничто, что я делаю, кажется, не может это исправить. Я пробовал

  • превращение validkeys в std :: set и data std :: map
  • с использованием const char * вместо строки
  • возвращает const double или double вместо const double &
  • с использованием списка и вектора вместо набора для хранения валидных ключей

Я не знаю, правильно ли я подхожу к этой проблеме, так что если есть какой-то другой простой способ создать класс, который обеспечивает такую ​​функциональность:

foo a;
a["foo2"] = a["foo1"] = 5.0;
// This would raise a std::runtime_error because I would be checking that
// "foo3" isn't in validkeys
a["foo3"] = 4.0;

Любые предложения с благодарностью.

РЕШЕНИЕ

Следующее работает точно так, как я хочу, у меня даже есть основное исключение, когда вы пытаетесь установить или получить ключ, которого нет в наборе допустимых ключей:

#include <iostream>
#include <string>
#include <map>
#include <set>
#include <stdexcept>

class myfooexception : public std::runtime_error
{
  public:
    myfooexception(const std::string & s)
      : std::runtime_error(s + " is not a valid key.") {}
};

class foo {
  public:
    foo() {
     for (std::set<std::string>::iterator it = validkeys.begin();
          it != validkeys.end();
          ++it) {
       data[*it] = 0.0;
     }
    }
    const double & operator[](const std::string & key) const {
      if (data.find(key) == data.end()) {
        throw myfooexception(key);
      } else {
        return data.find(key)->second;
      }
    }
    double & operator[](const std::string & key) {
      if (data.find(key) == data.end()) {
        throw myfooexception(key);
      } else {
        return data[key];
      }
    }
  private:
    static const std::set<std::string> validkeys;
    std::map<std::string, double> data;
};

const std::set<std::string> foo::validkeys = {"foo1", "foo2"};

int main(void)
{
  foo a;
  a["foo1"] = 2.0;
  a["foo1"] = a["foo2"] = 1.5;
  // a["foo3"] = 2.3; // raises exception:  foo3 is is not a valid key
  const foo b;
  std::cout << b["foo1"]; // should be ok
  // b["foo1"] = 5.0;  // compliation error, as expected: b is const.

  return 0;
}

Ответы [ 4 ]

3 голосов
/ 20 февраля 2012

operator [] не объявлено const в std::map, потому что operator [] также вставляет новый элемент, когда ключ не найден, и возвращает ссылку на его сопоставленное значение.Вы можете использовать метод map::find вместо map::operator[], если хотите, чтобы operator[] было const.

2 голосов
/ 20 февраля 2012

Оператор индекса для std::map не является константным, поскольку он вставляет новый элемент, если он еще не существует.Если вы хотите, чтобы ваша карта имела константу operator[], вам нужно написать ту, которая использует map::find() и проверяет соответствие map::end(), обрабатывая случай ошибки.

1 голос
/ 20 февраля 2012

вы пытаетесь изменить объект const !!пожалуйста, удалите const членов set.const, которые нельзя изменить после инициализации.

0 голосов
/ 20 февраля 2012

Вы пытаетесь присвоить std::map, но ваша функция объявлена ​​const и также возвращает const. Удалите оба const, и оно должно работать.

...