Range-v3:使用 view_facade 提供 const 和非常量迭代器
Range-v3: Use view_facade to provide both const and non-const iterators
我在使用 view_facade(来自 range-v3)创建同时提供 const 和非常量访问的视图时遇到问题。例如,我尝试修改 view_facade 测试(在 test/view_facade.cpp 中)以允许非 const 访问(默认情况下它只允许 const 访问):
struct MyRange
: ranges::range_facade<MyRange>
{
private:
friend struct ranges::range_access;
std::vector<int> ints_;
template <bool isConst>
struct cursor
{
private:
using It = typename std::conditional<isConst, std::vector<int>::const_iterator, std::vector<int>::iterator>::type;
using RefType = typename std::conditional<isConst, int const&, int&>::type;
It iter;
public:
cursor() = default;
cursor(It it)
: iter(it)
{}
RefType current() const
{
return *iter;
}
//...
};
/* // Uncommenting these overloads will cause an error, below.
cursor<true> begin_cursor() const
{
return {ints_.begin()};
}
cursor<true> end_cursor() const
{
return {ints_.end()};
}
*/
cursor<false> begin_cursor()
{
return {ints_.begin()};
}
cursor<false> end_cursor()
{
return {ints_.end()};
}
public:
MyRange()
: ints_{1, 2, 3, 4, 5, 6, 7}
{}
};
int main() {
MyRange nc;
int& nci = *nc.begin(); // error here when const overloads present.
}
这与注释掉 begin_cursor 和 end_cursor 的 const 重载很好用。但是,如果我重新添加这些重载,则会在指示的行 (GCC 5.1) 上生成以下错误:
error: binding 'const int' to reference of type 'int&' discards qualifiers
好像是选择了const版本,给了我一个const迭代器。我想要的是:const 对象的 const 迭代器,以及非常量对象的非常量迭代器。我怎样才能做到这一点?
view_facade
用于构建视图。视图指的是他们不拥有的数据。它们就像指针,因为它们在逻辑上是间接的。和指针一样,顶级 const
应该 对引用数据的 const
-ness 没有影响。也就是说,无论您取消引用 int*
还是 int*const
,结果都是一样的:int&
.
您的观点不是观点。它拥有自己的数据。 (请参阅 vector<int> ints_
数据成员。)尝试使用 view_facade
将此数据结构转换为视图势必会导致失败。这在很大程度上是设计使然。视图不同于容器。抱歉,Range-v3 库没有容器外观。
(发生了什么:由于视图表示间接,view_facade
非常努力地使 const 和非常量 begin()
和 end()
return 成为相同的类型。如果存在 cursor_begin() const
,则 总是 选择那个。总是。当这破坏代码时,通常是因为该代码混淆了容器和视图。)
我在使用 view_facade(来自 range-v3)创建同时提供 const 和非常量访问的视图时遇到问题。例如,我尝试修改 view_facade 测试(在 test/view_facade.cpp 中)以允许非 const 访问(默认情况下它只允许 const 访问):
struct MyRange
: ranges::range_facade<MyRange>
{
private:
friend struct ranges::range_access;
std::vector<int> ints_;
template <bool isConst>
struct cursor
{
private:
using It = typename std::conditional<isConst, std::vector<int>::const_iterator, std::vector<int>::iterator>::type;
using RefType = typename std::conditional<isConst, int const&, int&>::type;
It iter;
public:
cursor() = default;
cursor(It it)
: iter(it)
{}
RefType current() const
{
return *iter;
}
//...
};
/* // Uncommenting these overloads will cause an error, below.
cursor<true> begin_cursor() const
{
return {ints_.begin()};
}
cursor<true> end_cursor() const
{
return {ints_.end()};
}
*/
cursor<false> begin_cursor()
{
return {ints_.begin()};
}
cursor<false> end_cursor()
{
return {ints_.end()};
}
public:
MyRange()
: ints_{1, 2, 3, 4, 5, 6, 7}
{}
};
int main() {
MyRange nc;
int& nci = *nc.begin(); // error here when const overloads present.
}
这与注释掉 begin_cursor 和 end_cursor 的 const 重载很好用。但是,如果我重新添加这些重载,则会在指示的行 (GCC 5.1) 上生成以下错误:
error: binding 'const int' to reference of type 'int&' discards qualifiers
好像是选择了const版本,给了我一个const迭代器。我想要的是:const 对象的 const 迭代器,以及非常量对象的非常量迭代器。我怎样才能做到这一点?
view_facade
用于构建视图。视图指的是他们不拥有的数据。它们就像指针,因为它们在逻辑上是间接的。和指针一样,顶级 const
应该 对引用数据的 const
-ness 没有影响。也就是说,无论您取消引用 int*
还是 int*const
,结果都是一样的:int&
.
您的观点不是观点。它拥有自己的数据。 (请参阅 vector<int> ints_
数据成员。)尝试使用 view_facade
将此数据结构转换为视图势必会导致失败。这在很大程度上是设计使然。视图不同于容器。抱歉,Range-v3 库没有容器外观。
(发生了什么:由于视图表示间接,view_facade
非常努力地使 const 和非常量 begin()
和 end()
return 成为相同的类型。如果存在 cursor_begin() const
,则 总是 选择那个。总是。当这破坏代码时,通常是因为该代码混淆了容器和视图。)