У меня небольшая проблема с 2 операторами в моем классе.
Мой класс объявлен:
template <class keyType, class valueType>
class MyMap{
keyType keys[MAX];
valueType values[MAX];
int size;
}
Мне нужно переопределить оператор [], например, когда я звоню: std::cout<<MyMap1["a"];
,
keyType& operator[] (keyType key){}
Работает нормально. Я тоже использовал его для выполнения заданий, и это было хорошо, например: MyMap1["a"]="a1";
Код был идеальным. Но по моему operator[]
Я увеличиваю size
параметр, и это полезно только тогда, когда я хочу сделать назначение. Я не хочу увеличивать его, когда я делаю только std::cout
,
Так что, возможно, я должен переопределить operator=
функция, но когда я не могу написать:
void operator=(valueType value){}
Потому что левый член MyMap1["a"] = "a1"
это keyType
и не MyMap
тип.
Как я могу сделать ?
Проблема сама по себе не выводится; это то, что вы делаете, когда
Ключа нет Я думаю, что очень важно, чтобы вы указали
прежде чем идти дальше. Есть много возможностей:
Вы можете сделать что std::map
делает, и вставьте его по умолчанию
значение. Это очень удобно во многих случаях, но это значит
что вы не можете использовать []
на постоянной карте.
Вы можете сделать так, чтобы оператор возвращал указатель с нулевым значением
указатель, если объекта нет. Лично мне не нравится
это для operator[]
; это означает, что вы должны писать вещи
лайк: ValueType* p = myMap[ key ]; if ( p != NULL ) ...
, который
не кажется естественным для []
, (С другой стороны, это работает
хорошо с find
или же get
функция).
Вы можете выбросить исключение (или даже использовать assert, если вы
обеспечить contains
функция, и иметь его в качестве предварительного условия
[]
).
Вы можете вернуть предопределенное значение по умолчанию. Это своего рода
противоположность первого решения; это означает, что operator[]
никогда не будет менять карту, и что нет необходимости
неконстантная версия.
Наконец (и это, кажется, к чему вы стремитесь): вы
могу иметь operator[]
вернуть прокси, чтобы выделиться
между myMap["a"]
используется в качестве значения, и myMap["a"]
= something
, Я чувствую, что это решение не выходит замуж
хорошо с тем, как работает C ++, но он используется в других языках
(например, как Python).
Для последнего решения вы бы использовали что-то вроде:
class MyMap
{
class Proxy
{
MyMap* myOwner;
KeyType myKey;
public:
Proxy( MyMap* owner, KeyType key )
: myOwner( owner )
, myKey( key )
{
}
Proxy const& operator=( ValueType value ) const
{
myOwner->insertOrUpdate( myKey, value );
return *this;
}
operator ValueType() const
{
if ( !myOwner->contains( myKey ) ) {
throw UnknownKeyException( myKey );
}
return myOwner->get( myKey );
}
};
public:
Proxy operator[]( KeyType key )
{
return Proxy( this, key );
}
};
Если вы хотите различить операции чтения и записи, решение состоит в том, чтобы вернуть прокси-объект из operator []
,
Для примера см. https://stackoverflow.com/a/16132858/320726
Msgstr «Но в моем операторе [] я увеличиваю параметр размера».
Не. Проверьте, существует ли ключ, и увеличьте size
только если новый ключ вставлен. Когда вы делаете std::cout
предположительно вы делаете это только на существующих парах ключ / значение.
operator[]
, вернуть MyMap<KeyType, ValueType>::proxy
, Это оборачивает MyMap&
а также Key
, перегрузка MyMap::proxy::operator=(ValueType)
назначить новое значение и увеличить size
, перегрузка MyMap::proxy::operator ValueType() const
чтобы получить значение. Вернуть ValueType()
если ключа нету.
Когда вы пишете:
auto blah = map[key];
оператор [] вызывается с key
и возвращает значение.
Когда вы пишете:
map[key] = blah;
тогда оператор [ключ] вызывается с key
, и он возвращает значение, а затем оператор = вызывается на значение с blah
аргумент.
Это означает, что может быть трудно обнаружить, где вы на самом деле читаете или пишете на карту.
Однако, как правило, в случае чтения, случай может вернуться к value const& operator[] const
звонил, а во время записи было бы value& operator[]
без конст маркеры. Поэтому вы может быть попробуйте перегрузить оператор с помощью константного спецификатора: предоставьте 2 оператора [], один константный, один неконстантный, и увеличьте размер только в последнем.
Это простой легкий но не всегда будет работать правильно, как это может случиться в какой-то момент, чтобы случайно вызвать «operator [] as read», но без ограничения const, определяемого в этой точке компилятором. В настоящее время я не могу точно сказать, когда и как, и если это вообще возможно, но я полагаю, что вы можете ударить это довольно легко, если вы не очень осторожны с константностью.
Если вы нажмете это, то единственная известная мне опция — предоставить обертку для возвращаемого значения в неконстантном режиме и оставить нормальный для константного режима:
myMap::valueType const & operator[](key...) const
mymap::wrapper<myMap::valueType>& operator[](key...)
ваша обертка будет помнить ссылку& к вашей карте и запомните KEY, и эта обертка обеспечит неявное преобразование-TO-valueType, а также предоставит оператор присваивания FROM-valueType-TO-wrappertype. Неявный woudl-тип-преобразования-в-значение выполняет чтение из карты-из-под-данного ключа и не увеличивает счетчик, а оператор = (из-значения-в-тип-оболочки) выполняет запись в карту.
Это бы наверняка сработало, но такой подход может быть устаревшим. Я не бегу с изменениями c’11, так что, возможно, теперь есть более приятный вариант — например, переезд &&
семантика может что-то изменить здесь, то есть может быть перегрузка
valueType&& operator[](key)
тоже возможно —- но Я понятия не имею. Я знаю только подход «возврат прозрачной обертки».
РЕДАКТИРОВАТЬ: вот хороший (кажется полный) пример правильной перегрузки оператора [], которая поддерживает чтение и запись, и которая различает эти два:
стек: Как сделать некоторые вещи со значениями, назначенными в операторе индекса?
Вы увеличиваете свой size
только когда key
нет в keys
, право? Это то что std::map
делает. Так что, если вы просто печатаете содержимое карты, вы будете читать значения для существующих ключей, поэтому size
не будет увеличен