I'm trying to write a class View
to serve as a view into another container, (a sparse matrix class, but that should be unimportant for the question).
View
should contain references (e.g. std::reference_wrapper
) to a selection of elements in the container, and have methods returning references to those elements, as well as an assignment operator making one block equal to another.
My problem is that I want View
to be able to take values in addition to references: both be constructed from values as a non-reference instance to be used in assignments, and assign values to single elements in a reference instance.
An MVE of the code so far is:
#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);
}
};
It can be used like this:
#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;
}
This should output:
10 2
1 2 3 13 10
I'm using clang++
to compile on Ubuntu 15.10.
So specifically,
-
How should I implement the assignment operator to allow
View<T, size>
andView<std::reference_wrapper<T>, size>
to be assigned to each other (or at least the former to be assigned to latter). Creating two versionsView<T, size> & operator=(const View<T, size> & other); View<T, size> & operator=( const View<std::reference_wrapper<T>, size> & other);
does not work, (as a
View<std::reference_wrapper<T>, size>
then would need aView<std::reference_wrapper<std::reference_wrapper<T> >, size>
for the second overload). - How can I write the
get(size_t idx)
methods such that the return isT &
for bothView<T, size>
andView<std::reference_wrapper<T>, size>
?
I have a feeling this can be accomplished by using templates somehow, but I'm still quite new to template programming so I'm a bit lost.
Aucun commentaire:
Enregistrer un commentaire