考虑这段代码:
#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 有一个内置的解决方案来解决这个问题。
通过是否有相当于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) {}
};