包装类const正确性问题

时间:2013-07-03 20:19:16

标签: c++ c++11 const wrapper const-correctness

我正在尝试围绕JsonCpp的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;
}

2 个答案:

答案 0 :(得分:3)

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); }

但这并不妨碍任何人将返回值复制到非const Wrapper对象并使用它来改变Impl

答案 1 :(得分:0)

两个operator []的返回类型都不对吗?它应该分别是Impl&amp; / const Impl&amp;和