简体   繁体   中英

std::upper_bound returns const iterator in const member function

Here is a class that contains a boost::circular_buffer of some struct . I make a typedef for iterators into the contained circular_buffer .

My problem is this: when the doWork function is marked const , the returned value of std::upper_bound is not compatible with the MyIterator type due to the return value having boost::cb_details::const_traits . If I remove the const keyword from the function, all my compile errors go away.

To be clear the compiler error is this:

 error: conversion from 'boost::cb_details::iterator<boost::circular_buffer<Wrapper<int>::Sample, std::allocator<Wrapper<int>::Sample> >, boost::cb_details::const_traits<std::allocator<Wrapper<int>::Sample> > >' to non-scalar type 'Wrapper<int>::MyIterator {aka boost::cb_details::iterator<boost::circular_buffer<Wrapper<int>::Sample, std::allocator<Wrapper<int>::Sample> >, boost::cb_details::nonconst_traits<std::allocator<Wrapper<int>::Sample> > >}' requested [](const Sample& a, const Sample& b) { return a.foo < b.foo; }); 

Here is a self-contained example:

#include <algorithm>
#include <boost/circular_buffer.hpp>

template <typename T>
class Wrapper {
 public:
    struct Sample {
        T foo;
    };

    typedef typename boost::circular_buffer<Sample>::iterator MyIterator;

    Wrapper(int size) { cb.resize(size); }

    void add(T val) { cb.push_back(Sample{val}); }

    void doWork(T bound) const {
        MyIterator iter =
            std::upper_bound(cb.begin(), cb.end(), Sample{3},
                         [](const Sample& a, const Sample& b) { return a.foo < b.foo; });
    }

    boost::circular_buffer<Sample> cb;
};

int main() {
    Wrapper<int> buf(100);
    buf.add(1);
    buf.add(5);
    buf.doWork(3);
    return 0;
}

So, why can't this function be const? Why does marking it const have this side-effect? I want a non-const iterator into the container, but in my real test case I don't intend to actually modify the container at all.

You're going to need a const_iterator , since you're effectively observing a const container.

Perhaps:

typedef typename boost::circular_buffer<Sample>::const_iterator MyConstIterator;

… then make iter one of these.

Someone's going to tell you that you could have avoided this with auto . That's true, but then you never would have discovered this "bug", or that const_iterator s exist.

If your function is marked const then all your access to member variables will be const too.

A const container will only allow access to const_ iterators, that's just the way iterators work.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM