将视图类放入容器中
View class into a container
我试图写一个类View
作为另一个容器的视图,(一个稀疏矩阵类,但这应该是不重要的问题)。
View
应该包含对容器中元素选择的引用(例如std::reference_wrapper
),并具有返回对这些元素的引用的方法,以及使一个块等于另一个块的赋值操作符。
我的问题是,我希望View
能够接受值除了引用:两者都是从值构造为非引用实例中使用的赋值,并将值赋给引用实例中的单个元素。
目前为止代码的MVE是:
#include <array>
template<typename T, size_t size>
class View
{
private:
std::array<T, size> _values;
public:
View(const std::array<T, size> & values)
: _values{ values } { }
// ----------
View<T, size> & operator=(const View<T, size> & other)
{
for ( size_t i = 0; i < size; ++i ) {
this->get(i) = other.get(i);
}
return *this;
}
// ----------
T & get(size_t idx)
{
return _values.at(idx);
}
const T & get(size_t idx) const
{
return _values.at(idx);
}
};
可以这样使用:
#include <functional>
#include <iostream>
int main()
{
int values[5] = { 1, 2, 3, 4, 5 };
View<int, 2> v1{
{values[0], values[1]}
};
View<std::reference_wrapper<int>, 2> v2{
{values[3], values[4]}
};
// WHAT WORKS
v1.get(0) = 10; // can assign to the non reference `View<int, size>`,
// works as intended
v2.get(0) += 9; // can increment through the reference wrappers,
// this also works as intended
// WHAT THAT DOES NOT WORK
// v2 = v1; // nether of these work, as there is no conversion
// v1 = v2; // between `View<std::reference_wrapper<int>, size>`
// and `View<int, size>`. It is the first expression
// that is of most interest
// v2.get(1) = 10; // this doesn't work as the return is a
// `std::reference_wrapper<int>`, not a
// reference to an `int`
v2.get(1).get() = 10; // this works as a work-around to
// this problem, but it feels clunky, and it
// makes the interface between the two types
// different
for ( size_t i = 0; i < 2; ++i ) {
std::cout << v1.get(i) << " ";
}
std::cout << std::endl;
for ( size_t i = 0; i < 5; ++i ) {
std::cout << values[i] << " ";
}
std::cout << std::endl;
}
应该输出:
10 2
1 2 3 13 10
我用clang++
在Ubuntu 15.10上编译。
那么特别,
我应该如何实现赋值运算符,以允许
View<T, size>
和View<std::reference_wrapper<T>, size>
被分配给对方(或至少前者被分配给后者)。创建两个版本View<T, size> & operator=(const View<T, size> & other); View<T, size> & operator=( const View<std::reference_wrapper<T>, size> & other);
不工作,(因为
View<std::reference_wrapper<T>, size>
然后需要View<std::reference_wrapper<std::reference_wrapper<T> >, size>
进行第二次过载)。- 如何编写
get(size_t idx)
方法,使View<T, size>
和View<std::reference_wrapper<T>, size>
返回T &
?
我有一种感觉,这可以通过使用模板来完成,但我对模板编程仍然很陌生,所以我有点迷路了。
让get()
为T
和std::reference_wrapper<T>
返回T&
:
template <typename T>
struct get_value_type {
using type = T;
};
template <typename T>
struct get_value_type<std::reference_wrapper<T>> {
using type = T;
};
template<typename T, size_t size>
class View {
using value_type = typename get_value_type<T>::type;
value_type & get(size_t idx) {
return _values.at(idx);
}
const value_type & get(size_t idx) const {
return _values.at(idx);
}
};
get_value_type
模板帮助我们从T
和std::reference_wrapper<T>
中获得T
,然后您只需将get()
的返回类型更改为value_type
,并且由于std::reference_wrapper<T>
可以隐式转换为T&
,因此它可以工作。
现在您可以访问value_type
,您可以使用它来创建您的两个operator=
:
View& operator= (const View<value_type, size> & other) {
for (size_t i = 0; i < size; ++i) {
this->get(i) = other.get(i);
}
return *this;
}
View& operator=(const View<std::reference_wrapper<value_type>, size> & other) {
for (size_t i = 0; i < size; ++i) {
this->get(i) = other.get(i);
}
return *this;
}
如果你想允许从不同的视图分配(例如int
视图到double
视图),你可以使用模板化版本:
template <typename U>
View<T, size> & operator=(const View<U, size> & other) {
for (size_t i = 0; i < size; ++i) {
this->get(i) = other.get(i);
}
return *this;
}
一个可能有点偏离主题的小添加,但您可以从std::array
继承std::array
属性,如以下所示:
template<typename T, size_t Size>
struct View: public std::array<T, Size> {
using array_type = std::array<T, Size>;
using value_type = typename get_value_type<T>::type;
View (std::array<T, Size> const& values) : array_type (values) { }
View& operator=(const View<value_type, Size> & other) {
for (size_t i = 0; i < Size; ++i) {
(*this)[i] = other[i];
}
return *this;
}
View& operator=(const View<std::reference_wrapper<value_type>, Size> & other) {
for (size_t i = 0; i < Size; ++i) {
(*this)[i] = other[i];
}
return *this;
}
value_type & operator[](size_t idx) {
return array_type::operator[](idx);
}
const value_type & operator[](size_t idx) const {
return array_type::operator[](idx);
}
};
这将允许您在View
上使用标准库中的许多内容,而无需重新定义任何内容。
- 如何在选项卡视图Qt中设置一个新项目,并保存以前的项目
- 视图中的参数推导失败:take_while
- 如何维护资源管理器项目视图中当前可见的项目列表
- 在另一个类视图中添加最多2个图表的正确方法是什么
- OpenVR:向视图方向移动
- 使用 WIN32 API (C/C++) 对特定树视图项进行着色
- 将所选值(通过视图)从 boost::multi_array 复制到另一个数组 (C++)
- 如何在不使用滚动条的情况下使视图更改
- 列表视图更改选择颜色
- Qt - QVector 和模型视图 - 从列表视图获取自定义类的最佳方法是什么?
- 在 Qml 中从 QSqlTableModel 中删除单行时视图不一致
- 如何从未知视图中声明范围::v3::View 变量
- 控制带有信号/插槽的Qt QML滑动视图
- 列表视图项的替代颜色
- 带有 GDB 调试器的 VS 代码内存视图
- 如何将到达图形视图右侧(末端)的QGraphicsPixmapItem移动到左侧(开始)侧(就像在贪吃蛇游戏中发生的事情
- 从资源视图访问对话框时出现问题
- 范围修剪视图实现不适用于反向视图
- 从函数返回范围视图时,带有std::span:中间对象所有权的C++Ranges-v3
- 如何将 QString 的 QList 分配给列表视图?