Проблема корректности констант класса Wrapper

Я пытаюсь создать оболочку вокруг JsonCpp’s Json::Value,

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

Это минимальный пример.

// Impl is a typedef for Json::Value, from JsonCpp

namespace global
{
Impl& getChild(Impl& mImpl, const std::string& mName) { return mImpl[mName]; }
const Impl& getChildConst(const Impl& mImpl, const std::string& mName) { return mImpl[mName]; }

Impl::iterator beginNonConst(Impl& mRoot)           { return mRoot.begin(); }
Impl::iterator endNonConst(Impl& mRoot)             { return mRoot.end(); }
Impl::const_iterator beginConst(const Impl& mRoot)  { return mRoot.begin(); }
Impl::const_iterator endConst(const Impl& mRoot)    { return mRoot.end(); }
}

class Wrapper
{
private:
Impl& impl;

public:
Wrapper(Impl& mImpl) : impl(mImpl) { }

Wrapper operator[](const std::string& mName) { return global::getChild(impl, mName); }

// Error here
// no known conversion for argument 1 from 'const Impl {aka const Json::Value}' to 'Impl& {aka Json::Value&}'
const Wrapper operator[](const std::string& mName) const { return global::getChildConst(impl, mName); }

Impl::iterator begin()              { return global::beginNonConst(impl); }
Impl::iterator end()                { return global::endNonConst(impl); }
Impl::const_iterator begin() const  { return global::beginConst(impl); }
Impl::const_iterator end() const    { return global::endConst(impl); }
};

Это то, что я хочу иметь возможность компилировать:

int main()
{
Json::Value realValue;
Wrapper w(realValue)
for(const auto& i : w["numberArray"]) { cout << i << endl; }
for(auto& i : w["numberArray"]) { i += 100; }

// assert that changes have been made to realValue through the wrapper

return 0;
}

1

Решение

Wrapper имеет член типа Impl&, Делая Wrapper объект const меняет только верхний уровень const его членов (которые ничего не делают для ссылки, ссылки уже не подлежат повторному связыванию), и даже это вступает в силу только после завершения конструктора.

Вам нужен класс с членом типа const Impl&, а также const Wrapper не. Компилятор правильно предотвращает потерю const квалификатор и прохождение const Impl& в Wrapper::Wrapper(Impl&) что может изменить его аргумент.

В общем-то const_iterator это отдельный класс от iterator, Я не вижу причин, почему ваш Wrapper было бы по-другому.

В качестве краткосрочного решения вы можете просто использовать

const Wrapper operator[](const std::string& mName) const { return global::getChild(impl, mName); }

но это не мешает никому копировать возвращаемое значение в неконстантный Wrapper объект и использовать его для изменения Impl,

3

Другие решения

Не является ли тип возврата обоих операторов [] неправильным? Это должно быть Impl&/ const Impl&соответственно?

0

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector