Kev*_*vin 11 c++ language-lawyer c++20 std-ranges
假设我有一个将数据存储在地图中的自定义容器类:
class Container
{
public:
void add(int key, std::string value) { _data.emplace(key, std::move(value)); }
private:
std::map<int, std::string> _data;
};
Run Code Online (Sandbox Code Playgroud)
我想提供一个接口来访问地图的值(而不是键)。范围库提供了std::views::values地图值的范围:
auto values() { return std::views::values(_data); }
Run Code Online (Sandbox Code Playgroud)
用法:
Container c;
c.add(1, "a");
c.add(3, "b");
c.add(2, "c");
for (auto &value : c.values())
std::cout << value << " "; // Prints "a c b"
Run Code Online (Sandbox Code Playgroud)
但由于我想将我的类视为一个容器,所以我想要拥有begin()和end()迭代器。我可以这样做吗?
auto begin() { return std::ranges::begin(values()); }
auto end() { return std::ranges::end(values()); }
Run Code Online (Sandbox Code Playgroud)
在这里,我调用values()以获取映射值的范围,并获取到范围开头的迭代器(或哨兵结束迭代器)。但范围本身超出范围并被破坏。迭代器本身仍然有效吗?
从这个例子来看,迭代器似乎是有效的。std::views:values但是,无论是针对具体观点还是针对一般观点,标准是否保证了这一点?
\n\n视图迭代器在视图的生命周期之外是否有效?
\n
这里的属性称为借用范围。如果范围是借用范围,则即使范围被销毁,其迭代器仍然有效。R&如果R是一个范围,则它是最简单的借用范围 - 因为它不是迭代器所绑定的引用的生命周期。还有其他几个熟悉的借用范围 - 例如span和string_view。
一些范围适配器是有条件借用的(P2017)。也就是说,它们不会在正在调整的范围之上添加任何额外的状态——因此,如果基础范围是(或基础范围是),则可以借用调整后的范围。例如,views::reverse(r)无论何时借用,都是r借用的。但views::split(r, pat)不是有条件借用的 - 因为模式存储在适配器本身中而不是迭代器中(假设,它也可以存储在迭代器中,但需要付出一定的代价)。
views::values(r)就是一个这样的例子:只要r被借用,它就是一个借用的范围。并且,在您的示例中,基础范围是 a ref_view,它本身总是借用(按照始终借用的相同原则R&)。
请注意这里:
\nauto begin() { return std::ranges::begin(values()); }\nauto end() { return std::ranges::end(values()); }\nRun Code Online (Sandbox Code Playgroud)\nranges::begin仅当范围被借用时,传递右值范围才有效。那是[range.access.begin]/2.1:
\n\n如果
\nE是右值并且enable_\xc2\xadborrowed_\xc2\xadrange<remove_\xc2\xadcv_\xc2\xadt<T>>isfalse,ranges\xe2\x80\x8b::\xe2\x80\x8bbegin(E)则格式错误。
因此,因为您的原始代码已编译,所以您可以确定它是有效的。
\n| 归档时间: |
|
| 查看次数: |
510 次 |
| 最近记录: |