void foo(const auto& collection)
{
*collection.begin() = 104;
}
int main()
{
std::vector<int> ints {1, 2, 3, 4, 5};
foo(ints); // Error, as it should be
foo(ints | std::views::all); // Compiles and modifies the vector. Why?
return 0;
}
如果函数的参数是std::view
类型,为什么左值引用的constness被完全忽略?
编辑:
如果,正如你在评论中所写的,const视图引用类似于这种情况下的const指针,为什么代码不编译,如果相同的函数需要从右值对象构造的视图作为参数?
std::vector<int> getVec()
{
return std::vector{1, 2, 3, 4, 5};
}
void foo(const auto& collection)
{
*collection.begin() = 104; // Error: assignment of read-only location
}
int main()
{
foo(getVec() | std::views::all); // Nope!
return 0;
}
视图,尽管名称,不一定是不可修改的。一般来说,表示包含对象序列的类如何传播const
取决于使用的是什么类。这就是奇怪的地方。
看,views::all(e)
的返回类型改变取决于e
是什么。如果e
是一个glvalue(它本身不是一个视图),那么它返回e
表示的范围内的ref_view
。ref_view
的行为就好像它存储了一个指向给定范围的指针。当然,如果您有一个类的R*
成员,那么等价的const
是R * const
,而不是R const*
。因此,ref_view
不能将const
传播到所包含的范围。
然而,如果e
是一个右值(同样不是视图),那么all
返回的是一个owning_view
。该对象实际上将e
的副本存储为成员。这意味着当您获得const owning_view
时,该const
将传播到该成员。既然const vector<T>
会传播const
,那么views::all(e)
的右值也会传播vector
。