我正在尝试编写一个类View
作为另一个容器的视图(一个稀疏矩阵类,但这对于这个问题应该不重要)。
View
应该包含容器中选定元素的引用(例如std::reference_wrapper
),并且具有返回对这些元素的引用的方法,以及使一个块等于另一个的赋值运算符。
我的问题是我希望View
能够获取除引用之外的值:都可以从值构造为要在赋值中使用的非引用实例,并将值分配给a中的单个元素参考实例。
到目前为止,代码的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)
方法,使T &
和View<T, size>
的回报为View<std::reference_wrapper<T>, size>
?我有一种感觉,这可以通过某种方式使用模板来实现,但我仍然是模板编程的新手,所以我有点迷失。
答案 0 :(得分:2)
以下是get()
和T&
的{{1}}返回T
的方法:
std::reference_wrapper<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
获取T
,然后您只需将std::reference_wrapper<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);
}
};
标准库中的大量内容,而无需重新定义任何内容。