Указатель вызова С++ на элемент с картой из константной функции

У меня есть карта указателя на член, объявленный как:

std::map<char, T (Operand::*)(const T &, const T &)> op_map;

Я заполняю свою карту указателем на член непосредственно в конструкторе моего класса с помощью:

op_map['+'] = &Operand::op_add;

Например, исходный код op_add:

  T op_add(const T & a, const T & b) {
    return a + b;
  }

И я хочу вызвать свой указатель на член из константной функции. Вот исходный код:

  IOperand *res_int32(char op, const IOperand & rhs) const {
    IOperand *res = const_cast<IOperand *>(&rhs);
    Operand<int> *tmp = dynamic_cast<Operand<int>*>(res);
    T res_calc = (this->*op_map[op])(_value, (T)tmp->getValue());
  }

Но это всегда делает меня ошибкой:

Operand.hpp:70:64: error: passing ‘const std::map<char, double (Operand<double>::*)(const double&, const double&), std::less<char>, std::allocator<std::pair<const char, double (Operand<double>::*)(const double&, const double&)> > >’ as ‘this’ argument of ‘std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const key_type&) [with _Key = char, _Tp = double (Operand<double>::*)(const double&, const double&), _Compare = std::less<char>, _Alloc = std::allocator<std::pair<const char, double (Operand<double>::*)(const double&, const double&)> >, std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type = double (Operand<double>::*)(const double&, const double&), std::map<_Key, _Tp, _Compare, _Alloc>::key_type = char]’ discards qualifiers [-fpermissive]
Operand.hpp:70:64: error: invalid conversion from ‘const Operand<double>* const’ to ‘Operand<double>*’ [-fpermissive]

У вас есть какое-нибудь решение?

Спасибо.


person Jeffrey Muller    schedule 09.02.2012    source источник
comment
operator[] карты нельзя вызывать на const картах.   -  person R. Martinho Fernandes    schedule 09.02.2012
comment
Зачем тебе это const_cast? Operand<int>::getValue не объявлено const?   -  person Mike Seymour    schedule 09.02.2012


Ответы (3)


operator[] нельзя применить к карте const, поскольку она вставляет новый элемент, если ключ не найден.

В C++11 есть функция at, которая выдает исключение, если ключ не найден:

T res_calc = (this->*op_map.at(op))(_value, (T)tmp->getValue());
                           ^^^^^^^

В С++ 03 вам нужно будет использовать find:

map_type::const_iterator found = op_map.find(op);
if (found != op_map.end()) {
    T res_calc = (this->*(found->second))(_value, (T)tmp->getValue());
} else {
    // handle error
}

Вам также потребуется изменить тип функций-членов на карте на

T (Operand::*)(const T &, const T &) const
                                     ^^^^^

чтобы вызвать их на this из функции-члена const.

person Mike Seymour    schedule 09.02.2012

Просто сделайте op_add константной функцией-членом.

 T op_add(const T & a, const T & b) const // <<<
 {
   return a + b;
 }

И вместо std::map::operator[] используйте std::map::find http://www.cplusplus.com/reference/stl/map/find/

РЕДАКТИРОВАТЬ:

Вам также необходимо изменить тип карты на std::map<char, T (Operand::*)(const T &, const T &) const> op_map, как правильно указал Р. Мартиньо Фернандес.

person Gigi    schedule 09.02.2012
comment
И измените карту на std::map<char, T (Operand::*)(const T &, const T &) const> op_map. - person R. Martinho Fernandes; 09.02.2012
comment
@jeffrey, используйте map::find вместо map::operator[] - person Gigi; 09.02.2012

Если вы знаете, что делаете, вы можете попытаться скомпилировать с флагом С++ -fpermissive, как сказал G++.

person Adrien BARRAL    schedule 09.02.2012
comment
Если вы знаете, что делаете, то поймете, что это очень плохая идея. - person Mike Seymour; 09.02.2012
comment
Нет пожалуйста. -fpermissive включает слишком много вещей, которые вы никогда не хотели бы включать. Это слишком либерально. И вы всегда можете решить проблему с помощью реального решения без необходимости -fpermissive. - person R. Martinho Fernandes; 09.02.2012