如何让 `std::from_range` 在有意义时移动元素?

问题描述 投票:0回答:1

考虑这段代码:

#include <ranges>
#include <memory>
#include <list>
#include <vector>

template <typename T>
struct A
{
    std::vector<T> v;

    template <typename U>
    A(U &&input) : v(std::from_range, std::forward<U>(input)) {}
};

int main()
{
    A<std::unique_ptr<int>> a(std::list<std::unique_ptr<int>>{});
}

它无法编译,因为

std::from_range
尝试复制元素而不是移动它们。 在 gcc.godbolt.org 上运行

这里正确且惯用的解决方案是什么?如果源范围是右值并拥有元素,我希望它自动移动元素。


我知道

std::views::as_rvalue
存在,但决定何时应用它需要一个漫长的条件:

  • 输入范围必须是右值,并且
  • 它必须拥有元素(
    std::borrowed_range<U &> == false
    ,也许?不确定)

当然,我可以手动写出这个条件,但天真地希望 Ranges 有一个内置的解决方案来解决这个问题。

c++ std-ranges
1个回答
0
投票

通过是否有相当于std::forward的移动或复制等价物来实现std::ranges中的完美转发?,不仅没有内置解决方案,而且

std::borrowed_range<U> == false
也不是要检查的有效条件移动元素是否安全。

因此我们需要一些其他启发式方法来检查移动元素是否安全,也许是这样的:

#include <ranges>
#include <vector>

template <typename T>
concept IsOwningContainer = requires(std::remove_cvref_t<T> &t)
{
    t.erase(t.begin());
};

template <typename T>
struct A
{
    std::vector<T> v;

    template <typename U>
    A(U &&source) : v(std::from_range, source) {}

    template <typename U>
    requires (!std::is_reference_v<U>) && IsOwningContainer<U>
    A(U &&source) : v(std::from_range, source | std::views::as_rvalue) {}
};
© www.soinside.com 2019 - 2024. All rights reserved.