【问题标题】:Wrapper class const correctness issueWrapper 类 const 正确性问题
【发布时间】:2013-07-03 20:19:15
【问题描述】:

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

【问题讨论】:

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


    【解决方案1】:

    Wrapper 有一个 Impl&amp; 类型的成员。使Wrapper 对象const 仅更改其成员的顶级const(对引用没有任何作用,引用已经不可重新绑定),甚至只有在构造函数完成后才会生效。

    您需要一个具有const Impl&amp; 类型成员的类,而const Wrapper 不需要。编译器正确地防止您丢失const 限定符并将const Impl&amp; 传递给Wrapper::Wrapper(Impl&amp;),这可能会改变其参数。

    通常const_iterator 是一个独立于iterator 的类。我看不出你的Wrapper 有什么不同。

    作为一个短期的解决方案,你可以使用

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

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

    【讨论】:

    • 嘿,我是在 Zack 发表评论后才发现的,但你同时也在写你的答案 :)
    【解决方案2】:

    是不是两个operator[]的返回类型都错了?应该分别是Impl&/const Impl&吧?

    【讨论】:

    • 不一定。看起来 OP 依赖于对 Wrapper 的隐式转换。
    猜你喜欢
    • 2013-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-29
    相关资源
    最近更新 更多