std::set<std::unique_ptr<int>> 和 std::views::as_rvalue

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

我有以下代码,由于某种原因,只有最后一个块不起作用。

我最初认为这可能与

unique_ptr
仅移动或
std::set
具有 const 键有关,但随后不清楚为什么其他块起作用。



namespace sr = std::ranges;
namespace sv = std::views;
int main() {
    {
        std::set<int> up_s{10,20};
        const auto up_vec = sv::as_rvalue(up_s) | sr::to<std::vector>();
        assert(up_vec.size() == 2);
    }
    {
        std::vector<std::unique_ptr<int>> up_d;
        up_d.emplace_back(std::make_unique<int>(10));
        up_d.emplace_back(std::make_unique<int>(20));
        const auto up_vec =  sv::as_rvalue(up_d) | sr::to<std::vector>();
        assert(up_vec.size() == 2);
    }    
    {
        std::set<std::unique_ptr<int>> up_d;
        up_d.emplace(std::make_unique<int>(10));
        up_d.emplace(std::make_unique<int>(20));
        //const auto up_vec =  sv::as_rvalue(up_d) | sr::to<std::vector>();
        //assert(up_vec.size() == 2);
    }        
}

错误消息似乎没用,因为看起来由于某种原因代码想要将

unique_ptr
视为范围

/opt/compiler-explorer/gcc-trunk-20240513/include/c++/15.0.0/ranges:9354:25:错误:静态断言失败 9354 | 9354 static_assert(input_range>); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /opt/compiler-explorer/gcc-trunk-20240513/include/c++/15.0.0/ranges:9354:25:注意:不满足约束

...

/opt/compiler-explorer/gcc-trunk-20240513/include/c++/15.0.0/bits/ranges_base.h:499:13: 满足 'range<_Tp>' [with _Tp = const std::unique_ptr&&] /opt/compiler-explorer/gcc-trunk-20240513/include/c++/15.0.0/bits/ranges_base.h:499:21: 在 '_Tp& __t' 的要求中 [with _Tp = const std::unique_ptr&&] /opt/compiler-explorer/gcc-trunk-20240513/include/c++/15.0.0/bits/ranges_base.h:501:22: 注意:所需的表达式 'std::ranges::_Cpo::begin(__t)' 是 无效 501 |范围::开始(__t); | ~~~~~~~~~~~~~^~~~~ /opt/compiler-explorer/gcc-trunk-20240513/include/c++/15.0.0/bits/ranges_base.h:502:20: 注意:所需的表达式 'std::ranges::_Cpo::end(__t)' 无效 502 | 502范围::结束(__t);

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

我最初认为这可能与

unique_ptr
仅移动或
std::set
具有
const
键有关,但随后不清楚为什么其他块起作用。

你说得一针见血。很难从错误中辨别出来,而且我无法生成一些使其显而易见的错误消息,但简而言之,问题是

std::set
只能让我们访问
const
键,而
std::unique_ptr
会需要一些非常量才能使移动成为可能。

通过

as_rvalue
传输此范围并不能解决此问题;这只是意味着我们正在使用一系列类型为
const std::unique_ptr
的 xvalue,但这并不好。以下代码格式不正确,您尝试创建向量也是如此:

const std::unique_ptr<int> p;
auto q = std::move(p); // call to deleted copy constructor, ill-formed

其他案例

std::set<int>
的情况下,常量并不重要。
std::set<int>
const int
左值的范围,通过管道将其通过
as_rvalue
使其成为
const int
x 值的范围。 下面的代码很好,从这样的范围构造
std::vector<int>
也可以:

const int x = 0;
int y = std::move(x); // initialization of an int from an xvalue of type const int

std::vector<std::unique_ptr<int>>
的情况下,常量不是问题。
std::vector
为我们提供了对元素的非常量访问,因此通过
as_rvalue
进行管道传输为我们提供了一系列非常量
std::unique_ptr
xvalues。 因此,将为每个元素调用移动构造函数。

© www.soinside.com 2019 - 2024. All rights reserved.