有没有可能使用转换后的迭代器获取原始值的方法?
Is there any possible way to get origin value using transformed iterator?
C++20 引入了 views::elements
、views::keys
和 views::values
来轻松处理类元组值的范围:
std::vector v{std::tuple{'A', 1}, {'B', 2}, {'C', 3}};
auto it = std::ranges::find(v | std::views::elements<0>, 'B');
assert(*it == 'B');
应用适配器后,v | std::views::elements<0>
成为每个元组第一个元素的范围,因此 ranges::find
的 return 类型是该转换范围的迭代器类型。
但是有没有办法将it
转换回原始迭代器类型以获得原始元组?
assert(*magic_revert(it) == std::tuple{'B', 2});
没有从 it
到原始元组的真正方法,因为 it
指向由原始元组范围构造的 view
。
你可以很容易地解决这个问题:
auto elems = v | std::views::elements<0>; // name the view
auto it = std::ranges::find(elems, 'B'); // find it
// use the distance of it from the beginning of elems, to get an iterator into v
auto orig_it = std::next(std::begin(v),
std::distance(std::begin(elems), it));
可以通过调用 .base()
.
获取指向基础范围的迭代器
assert(*it.base() == std::tuple{'B', 2});
但是使用带有 std::ranges::find
的投影可能更符合习惯。
std::vector v{std::tuple{'A', 1}, {'B', 2}, {'C', 3}};
auto it = std::ranges::find(v, 'B', [](auto& e) { return std::get<0>(e); });
assert(*it == std::tuple{'B', 2});
C++20 引入了 views::elements
、views::keys
和 views::values
来轻松处理类元组值的范围:
std::vector v{std::tuple{'A', 1}, {'B', 2}, {'C', 3}};
auto it = std::ranges::find(v | std::views::elements<0>, 'B');
assert(*it == 'B');
应用适配器后,v | std::views::elements<0>
成为每个元组第一个元素的范围,因此 ranges::find
的 return 类型是该转换范围的迭代器类型。
但是有没有办法将it
转换回原始迭代器类型以获得原始元组?
assert(*magic_revert(it) == std::tuple{'B', 2});
没有从 it
到原始元组的真正方法,因为 it
指向由原始元组范围构造的 view
。
你可以很容易地解决这个问题:
auto elems = v | std::views::elements<0>; // name the view
auto it = std::ranges::find(elems, 'B'); // find it
// use the distance of it from the beginning of elems, to get an iterator into v
auto orig_it = std::next(std::begin(v),
std::distance(std::begin(elems), it));
可以通过调用 .base()
.
assert(*it.base() == std::tuple{'B', 2});
但是使用带有 std::ranges::find
的投影可能更符合习惯。
std::vector v{std::tuple{'A', 1}, {'B', 2}, {'C', 3}};
auto it = std::ranges::find(v, 'B', [](auto& e) { return std::get<0>(e); });
assert(*it == std::tuple{'B', 2});