c++ - 使用相同 std::view 的两个不同拷贝

标签 c++ std-ranges

我尝试在商业应用程序中使用 View ,并注意到 gcc 和 Visual Studio 之间的不一致。

在下面的代码中,调用 transformed()两次返回两个不同的、显然不兼容的 View 。在 gcc 11(在 godbolt 上)中,即使进行了额外的调试,代码执行也没有问题,但在 Visual Studio 16.11 中 -std:c++latest ,它断言:

cannot compare incompatible transform_view iterators

我希望我的函数可以被调用,就像它返回 const std::vector<std::pair<int, int>> & 一样。所以调用者不必担心临时变量。看来我可以使我的转换 View 成为我的类的成员,在构造函数中初始化它,然后返回它,但我什至不知道如何声明它。

我假设 Visual Studio 是正确的,而我的代码是非法的,但即使我的代码应该合法,它仍然必须工作。我们拥有 10,000,000 行代码库和许多非专业 C++ 程序员,我需要核心足够强大,并且没有像这样的隐藏陷阱。

#include <iostream>
#include <ranges>
#include <vector>

struct X
{
    std::vector<int> m_values{ 1,2,3 };
    auto transformed() const
    {
        return std::ranges::views::transform(m_values, [](int i) {
            return std::pair{ i, i + i };
            });
    }
};

int main()
{
    X x;
    for (auto [a, b] : x.transformed())
        std::cout << a << " " << b << std::endl;

    if (x.transformed().begin() != x.transformed().end()) // asserts in visual studio.
        std::cout << "not empty";

    return 0;
}

https://godbolt.org/z/hPWYGn9dY

最佳答案

It seems that I could make my transformed view a member of my class, initialize it in the constructor, and return that, but I don't even know how to declare it.

您可以将X转换为模板类,并通过传递的lambda构造成员transform_view,如下所示:

#include <iostream>
#include <ranges>
#include <vector>

template<class F>
struct X {
  std::vector<int> m_values{1,2,3};
  decltype(m_values | std::views::transform(std::declval<F>())) m_transformed;

  X(F fun) : m_transformed(m_values | std::views::transform(std::move(fun))) { }
  const auto& transformed() const { return m_transformed; }
};

int main() {
  X x([](int i) { return std::pair{i, i + i}; });
  for (auto [a, b] : x.transformed())
    std::cout << a << " " << b << std::endl;

  if (x.transformed().begin() != x.transformed().end())
    std::cout << "not empty";
}

Demo.

另一种方法是使用 std::function,这使得您的 X 不必是模板类:

struct X {
  using Fun = std::function<std::pair<int, int>(int)>;
  std::vector<int> m_values{1,2,3};
  decltype(m_values | std::views::transform(Fun{})) m_transformed;

  X(Fun fun = [](int i) { return std::pair{i, i + i}; }) 
  : m_transformed(m_values | std::views::transform(std::move(fun))) { }
  const auto& transformed() const { return m_transformed; }
};

Demo.

关于c++ - 使用相同 std::view 的两个不同拷贝,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70039388/

相关文章:

c++ - 在 C++ 中编写自定义异常

c++ - 在类外访问私有(private)静态变量

c++ - 纠结于计算学校的 C++ 日历代码

c++ - C++20 keys_view 和 values_view 的真正目的是什么?

c++ - 检查类型是否/可转换为 c++20 中的范围

c++ - 在使用基于概念的递归功能模板推导 'auto […] '之前使用 'auto'

c++ - 为什么 C++ 中没有多方法?

c++ - visual C++ express 2010 和设置环境变量解决方案范围

c++ - C++20 范围是否具有过滤器或 any_of 的值(非谓词)版本?

c++ - 为什么 Ranges 库中的 std::views::take_while 需要 const 谓词?