Const转换std容器

时间:2014-06-16 22:58:41

标签: c++ c++11

考虑一下我有一个std :: vector。

std::vector<int> blah;
blah.push_back(1);
blah.push_back(2);

我现在想要在某处传递向量并禁止修改其包含的对象的内容,同时仍允许在能够修改容器时使用:

// Acceptable use:
void call_something() {
    std::vector<int> blah;
    blah.push_back(1);
    blah.push_back(2);

    // Currently, compiler error because of mismatching types
    something(blah);
}

void something(std::vector<const int>& blah)
{
    // Auto translates to 'const int'
    for ( auto& i : blah ) {
        // User cannot modify i.
        std::cout << i << std::endl;
    }
    blah.push_back(blah.size()); // This should be acceptable
    blah.emplace_back(); // This should be acceptable
    return;
}

// Unacceptable use:
void something_else(const std::vector<int>& blah)
{
    // Because of const vector, auto translates to 'const int'
    for ( auto& i : blah ) {
        std::cout << i std::endl;
    }
    blah.push_back(blah.size()); // This will present an unacceptable compiler error.
    blah.emplace_back(); // This will present an unacceptable compiler error.
    return;
}

有一种简单的方法吗?

2 个答案:

答案 0 :(得分:2)

没有 easy 方法可以做到这一点。一种方法是将vector包装在仅公开您要允许的功能的类型中。例如

template<typename T, typename A = std::allocator<T>>
struct vector_wrap
{
    using iterator = typename std::vector<T, A>::const_iterator;
    using const_iterator = typename std::vector<T, A>::const_iterator;
    using size_type = typename std::vector<T, A>::size_type;

    vector_wrap(std::vector<T, A>& vec)
    : vec_(&vec)
    {}

    void push_back(T const& value) { vec_->push_back(value); }
    void push_back(T&& value) { vec_->push_back(std::move(value)); }
    size_type size() { return vec_->size(); }
    iterator begin() const { return vec_->cbegin(); }
    iterator end() const { return vec_->cend(); }

private:
    std::vector<T, A> *vec_;
};

由于上述实现仅存储指向其vector的指针,因此您必须确保vector的生命周期长于vector_wrap的生命周期。

您必须修改somethingsomething_else,以便他们以vector_wrap<int>作为参数。由于vector_wrap::beginvector_wrap::end返回const_iterator,因此您不得修改for语句中的现有元素。

Live demo

答案 1 :(得分:2)

要启用您希望允许的操作,同时防止其他操作,您需要对功能的界面采用细粒度的方法。例如,如果您的调用代码是传递const迭代器(开始和结束)以及后插入器(或自定义后置放置器仿函数),那么您显示的操作子集就是可能的。

template <class Iter, class F>
void something(Iter begin, Iter end, F&& append)
{
    using value_type = typename std::iterator_traits<Iter>::value_type;
    std::copy(begin, end, std::ostream_iterator<value_type>(std::cout, "\n"));
    append(std::distance(begin, end));
    append();
    return;
}

那说我发现你的例子特别引人注目。你有一个真实的场景,你必须维护可变元素,将一个可变容器传递给一个函数,然后将传递的元素视为不可变的吗?