![](/img/trans.png)
[英]Assign std::vector<std::unique_ptr<T>> to another std::vector<std::unique_ptr<T>>
[英]Returning a range of references to a std::vector<std::unique_ptr<T>>
我有一个抽象基础 class T
和另一个 class 持有指向T
的唯一指针向量。 class 应该支持两个 function 返回对条目的引用。 其中一个应该提供读取访问权限,另一个应该能够修改unique_ptr
中的值,但不能修改指针:
class A {
private:
std::vector<std::unique_ptr<T>> data;
public:
auto access() -> RefRange<T>;
auto const_access() -> ConstRefRange<T>;
};
范围应满足std::random_access_range
的要求。 如果不在 C++17 中分配额外的 memory(升压可用),我该如何做到这一点?
如果你有提升,这大部分是由范围适配器indirected
完成的
class A {
private:
static auto add_const(T & t) -> const T & { return t; }
std::vector<std::unique_ptr<T>> data;
using indirected = boost::adaptors::indirected;
using transformed = boost::adaptors::transformed;
public:
auto access() { return data | indirected; }
auto const_access() const { return data | indirected | transformed(add_const); }
};
或者在 C++20 中使用std::views::transform
class A {
private:
static auto indirect(const std::unique_ptr<T> & ptr) -> T & { return *ptr; }
static auto add_const(T & t) -> const T & { return t; }
std::vector<std::unique_ptr<T>> data;
using transform = std::views::transform;
public:
auto access() { return data | transform(indirect); }
auto const_access() const { return data | transform(indirect) | transform(add_const); }
};
如果你有<experimental/propagate_const>
,我会用它来代替transform(add_const)
。
class A {
private:
std::vector<std::experimental::propagate_const<std::unique_ptr<T>>> data;
using indirected = boost::adaptors::indirected;
public:
auto access() { return data | indirected; }
auto const_access() const { return data | indirected; }
};
您可以实现一个包装器类型,它包装std::vector::iterator
并在取消引用时提供对std::unique_ptr
包含的元素的引用。 然后返回一个包含这些类型的开始和结束迭代器的简单结构。
前任:
template<class T>
struct MyIterator
{
typename std::vector<std::unique_ptr<T>>::iterator iter; // or const_iterator for the const version
decltype(auto) operator*() const { return *iter->get(); }
// implement the rest of the iterator functionality
// ...
};
template<class T>
struct RefRange
{
MyIterator<T> first, last;
auto begin() const { return this->first; }
auto end() const { return this->last; }
};
class A {
private:
std::vector<std::unique_ptr<T>> data;
public:
auto access() -> RefRange<T> { return { data.begin(), data.end() }; }
};
围绕迭代器的包装器是我想到的第一件事。 这是一个快速而肮脏的例子,但你应该明白我的想法。
演示: https://godbolt.org/z/z365js1T9
#include <memory>
#include <vector>
#include <iostream>
#include <initializer_list>
template<typename T>
struct S
{
using VecType = std::vector<std::unique_ptr<T>>;
VecType v{};
class RefRange
{
public:
RefRange(VecType& v) : r{v} {}
struct iterator
{
typename VecType::iterator underlying_iterator;
//below just return const T& for ConstRefRange
T& operator*() const { return *underlying_iterator->get();}
iterator& operator++(){++underlying_iterator; return *this;}
iterator operator++(int) {iterator ret{*this}; ++(*this); return ret;}
friend bool operator==(const iterator& l, const iterator& r)
{
return l.underlying_iterator==r.underlying_iterator;
}
friend bool operator!=(const iterator& l, const iterator& r)
{
return !(l==r);
}
};
iterator begin() {return iterator{r.begin()};}
iterator end() {return iterator{r.end()};}
private:
VecType& r;
};
RefRange refs() {return RefRange{v};}
};
int main()
{
S<int> s;
s.v.push_back(std::make_unique<int>(5));
s.v.push_back(std::make_unique<int>(6));
s.v.push_back(std::make_unique<int>(7));
auto r = s.refs();
for (auto&& el : r) {std::cout << el;}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.