std::upper_bound returns const 成员函数中的 const 迭代器
std::upper_bound returns const iterator in const member function
这是一个 class,其中包含一些 struct
的 boost::circular_buffer
。我为包含的 circular_buffer
中的迭代器创建了一个 typedef。
我的问题是:当 doWork
函数被标记为 const
时,std::upper_bound
的 returned 值与 MyIterator
不兼容由于 return 值具有 boost::cb_details::const_traits
类型。如果我从函数中删除 const
关键字,我所有的编译错误都会消失。
要清楚编译器错误是这样的:
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; });
这是一个独立的例子:
#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;
}
那么,为什么这个函数不能是常量?为什么将其标记为 const 会产生这种副作用?我想要一个非常量迭代器到容器中,但在我的真实测试用例中,我根本不打算实际修改容器。
您将需要一个 const_iterator
,因为您正在有效地观察一个 const
容器。
也许:
typedef typename boost::circular_buffer<Sample>::const_iterator MyConstIterator;
…然后使iter
成为其中之一。
有人会告诉您,您可以使用 auto
避免这种情况。没错,但是你永远不会发现这个 "bug",或者 const_iterator
的存在。
如果你的函数被标记为 const
那么你对成员变量的所有访问也将是 const
。
const
容器将只允许访问 const_
迭代器,这就是迭代器的工作方式。
这是一个 class,其中包含一些 struct
的 boost::circular_buffer
。我为包含的 circular_buffer
中的迭代器创建了一个 typedef。
我的问题是:当 doWork
函数被标记为 const
时,std::upper_bound
的 returned 值与 MyIterator
不兼容由于 return 值具有 boost::cb_details::const_traits
类型。如果我从函数中删除 const
关键字,我所有的编译错误都会消失。
要清楚编译器错误是这样的:
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; });
这是一个独立的例子:
#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;
}
那么,为什么这个函数不能是常量?为什么将其标记为 const 会产生这种副作用?我想要一个非常量迭代器到容器中,但在我的真实测试用例中,我根本不打算实际修改容器。
您将需要一个 const_iterator
,因为您正在有效地观察一个 const
容器。
也许:
typedef typename boost::circular_buffer<Sample>::const_iterator MyConstIterator;
…然后使iter
成为其中之一。
有人会告诉您,您可以使用 auto
避免这种情况。没错,但是你永远不会发现这个 "bug",或者 const_iterator
的存在。
如果你的函数被标记为 const
那么你对成员变量的所有访问也将是 const
。
const
容器将只允许访问 const_
迭代器,这就是迭代器的工作方式。