c++ - 将 std::ranges::view 类型对象传递给类的正确方法是什么?

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

这个问题涉及 std::ranges::view类型对象作为类的成员变量。我试图更好地理解它们,所以我可能会在这里编写一些糟糕的代码!

假设我们有一个函数 foo()它与某些数据源交互并返回 std::tuple范围 View 数:

auto foo(int i)
{
  auto v1 = views::iota(i) | views::transform([](int i){ return i++; });
  auto v2 = views::iota(i) | views::filter([](int i){ return i % 2; });
  auto v3 = views::iota(i) | views::transform([](int i){ return i += 3; });
  return std::make_tuple(v1,v2,v3);
}

然后我们需要做一些处理,其中涉及 foo() 的三个返回 View ,它们之间存在一定的相互依赖关系。因此,我想将它们存储为类的成员,但我想避免复制整个底层数据,所以我这样做:

template<ranges::view Vx, ranges::view Vy, ranges::view Vz>
struct Processor
{
public:
    Processor(Vx&& x, Vy&& y, Vz&& z) : m_x{x}, m_y{y}, m_z{z} {}

    auto bar() { /* work using m_x, m_y and m_z */ }

private:
    Vx m_x;
    Vy m_y;
    Vz m_z;
};

在这种情况下,我必须初始化 Processor 的实例使用std::move ,像这样:

auto [x,y,x] = foo(10);
Processor p(std::move(x), std::move(y), std::move(z));

或者,我选择 x , yzProcessor 构造函数中的值即Processor(Vx x, Vy y, Vz z) : m_x{x}, m_y{y}, m_z{z} {}然后可以构造一个实例:

auto [x,y,x] = foo(10);
Processor p(x, y, z);

所以,我想澄清一下(a)这是否是一个好主意以及(b)我应该对这两种方法采取哪种方法?我怀疑按值传递是正确的(值语义,对吧?),因为我们不复制底层数据,只复制每个数据的 View 。

最后有没有办法约束Processor的模板参数此外,例如写类似 ranges::view<int> 的内容当我将每个范围传递给构造函数时,我是否知道它的基础类型?

谢谢!神 bolt 链接:https://godbolt.org/z/Gx419949n

最佳答案

View 通常按值传递,因为通常它不拥有数据,它只是保留指向数据的指针(当然也有一些异常(exception),例如single_view),因此处理器(Vx x, Vy y, Vz z) 应该是首选。

但是,请务必注意, View 保证可移动。例如,标准 owning_view 是仅移动 View ,因此您应该确保将值移动到成员初始值设定项列表中的成员

template<ranges::view Vx, ranges::view Vy, ranges::view Vz>
struct Processor
{
public:
  Processor(Vx x, Vy y, Vz z) 
    : m_x{std::move(x)}, m_y{std::move(y)}, m_z{std::move(z)} {}
private:
  Vx m_x;
  Vy m_y;
  Vz m_z;
}

Finally, is there any way to constrain the template parameters of Processor further, for example writing something like ranges::view if I know the underlying type of each range when I pass it to the constructor?

您可以使用requires子句进行额外的约束检查

template<ranges::view Vx, ranges::view Vy, ranges::view Vz>
  requires std::same_as<std::ranges::range_value_t<Vx>, int> && 
           std::same_as<std::ranges::range_value_t<Vy>, int> && 
           std::same_as<std::ranges::range_value_t<Vz>, int>
struct Processor {
  // ...
};

关于c++ - 将 std::ranges::view 类型对象传递给类的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75548823/

相关文章:

c++ - SFINAE 检测 CTAD 演绎指南的明确性

c++ - C++20 范围适配器的递归应用导致编译时无限循环

c++ - boost::range::combine 不适用于 std::subrange

c++ - 我安装了 mingw32-pthreads-w32 但我仍然无法编译 std::mutex

c++ - C++ 11中线程的延迟启动

c++ - 公斤到磅转换器构建错误 (CLion)

c++ - std::time_point往返于std::string

c++ - 如何从 YUV 图像流生成 VBR 视频?

c++ - 我怎样才能为唯一的类组合获得一致的、唯一的标识符?

c++ - 使用范围拆分 string_view