c++ - std::views::keys 是否保证能与任何对/元组类型正常工作?

标签 c++ c++20 std-ranges

代码粘贴在此处& https://www.godbolt.org/z/qszqYsT4o

我正在尝试提供boost::adaptors::indexed与 c++20 View 兼容的功能。我的主要用例是 std::vector ,但我肯定更喜欢通用的解决方案。我震惊地发现std::views::keys没有按预期正确提取第一个元素。

对于 GCC 10.3,输出 rng1是垃圾并且rng2正如预期的那样。 GCC 10.4+ 工作正常。 最新版本的 clang 无法编译代码。

问题:

  1. std::views::keys保证支持任何对/元组类型,或者我的代码是UB?
  2. 鉴于 clang 14.0.0 无法编译,我的代码是否合法 C++?
  3. 在 c++20 中是否有更好的方法来实现此功能?我在看std::span有一段时间,但似乎无法让它自然地发挥作用。注意:我很乐意使用 std::views::zipstd::views::iota如果有的话。
#include <vector>
#include <ranges>
#include <iostream>

template <typename T>
using IndexValuePair = std::pair<std::size_t, std::reference_wrapper<T>>;

template <typename T, typename Allocator>
auto make_indexed_view(std::vector<T, Allocator>& vec)
{
    auto fn = [&vec](T& val) {
        return IndexValuePair<T>{static_cast<std::size_t>(&val - vec.data()), val};
    };
    return std::views::all(vec) | std::views::transform(fn);
}

template <typename T, typename Allocator>
auto make_indexed_view(const std::vector<T, Allocator>& vec)
{
    auto fn = [&vec](const T& val) {
        return IndexValuePair<const T>{static_cast<std::size_t>(&val - vec.data()), val};
    };
    return std::views::all(vec) | std::views::transform(fn);
}

struct GetFirstSafely {
    template <typename T1, typename T2>
    const T1& operator()(const std::pair<T1, T2>& p) const { return std::get<0>(p); }

    template <typename T1, typename T2>
    T1 operator()(std::pair<T1, T2>&& p) const { return std::get<0>(std::move(p)); }
};

auto get_first = [](auto&& p) -> decltype(auto) { return GetFirstSafely{}(std::forward<decltype(p)>(p)); };

int main()
{
    const std::vector<int> v{10, 20, 30};
    auto fn = [](const auto& val) { return val.second >= 20; };
    auto rng1 = make_indexed_view(v) | std::views::filter(fn) | std::views::keys;
    auto rng2 = make_indexed_view(v) | std::views::filter(fn) | std::views::transform(get_first);
    for (auto&& elem : rng1)
        std::cout << elem << '\n';
    for (auto&& elem : rng2)
        std::cout << elem << '\n';
    return 0;
}

最佳答案

Is std::views::keys guaranteed to support any pair/tuple type, or is my code UB?

views::keys保证与 pair 一起工作/tuple在 C++20 中,并且保证可以与 tuple-like 一起使用 C++23 中的对象感谢 P2165 .

Given clang 14.0.0 fails to compile, is my code legal C++?

您的代码格式正确。

但是,没有必要使用 reference_wrapper ,一个简单的pair<size_t, T&>应该够用了,没必要用std::views::all(vec) , vec | views::transform(fn)会自动转换vecview .

Is there a better way to achieve this functionality in c++20?

在 C++20 中,恐怕不是。在 C++23 中,您可以编写 views::iotaviews::zip为此,例如

const std::vector<int> v{10, 20, 30};
for (const auto& [index, value] : views::zip(views::iota(0uz, v.size()), v))
  std::cout << index << " " << value << "\n";

在 C++26 中,您可以使用 views::enumerate (如果被采纳)

const std::vector<int> v{10, 20, 30};
for (const auto & e : views::enumerate(v))
  std::cout << e.index << " " << e.value << "\n";

关于c++ - std::views::keys 是否保证能与任何对/元组类型正常工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73177944/

相关文章:

c++ - 通知 QAbstractItemView 更改的最佳方式是什么

c++ - 编译时断言?

c++ - C++ 的模块标准是否解决了对调用者隐藏私有(private)数据的问题?

c++ - RVO 何时保证适用/确实适用于 C++20 编译器

c++ - 为什么我不能使用 istream_view 和 std::accumulate 来总结我的输入?

c++ - 如何从 Http 请求处理程序正确终止 POCO ServerAPPLICATION

c++ - 一起使用 cppcoro 和 ASIO 的 co_spawn

C++20 范围和排序

c++ - 为什么 ranges::view_interface<T>::size 需要移动构造函数

c++ - 在 C++ 中执行主程序时,如何在后台检查是否已经过了一分钟?