Reputation: 1147
The example below is degenerate because I would like to learn about the concept.
Let's say we would like to have a 1-element view
of an array.
My question is how to make it work with both const
and non-const
objects.
I know why the second block in the code below does not compile but I don't know how to organize the code to serve both cases.
#include <cassert>
#include <array>
template <typename T>
class View {
private:
const std::size_t index_;
T &t_;
using value_type = typename T::value_type;
public:
View(T &t, std::size_t index) : t_{t}, index_{index} {}
const value_type &value() const { return t_[index_]; }
value_type &value() { return t_[index_]; }
};
int main() {
using Array = std::array<int, 2>;
// The block below works
{
Array array{0, 0};
View<Array> view(array, 0);
view.value() = 5;
assert(array[0] == 5);
}
// The block below gives a compilation error
{
const Array array{5, 5};
View<Array> view(array, 0);
assert(view.value() == 5);
}
}
Upvotes: 2
Views: 74
Reputation: 5095
The following works:
#include <cassert>
#include <array>
template <typename T>
class View {
private:
using value_type = typename T::value_type;
T &t_;
const std::size_t index_;
public:
View(T &t, std::size_t index) : t_{t}, index_{index} {}
const value_type &value() const { return t_[index_]; }
template<class Arr = T, class = typename std::enable_if<!std::is_const<Arr>::value>::type>
value_type &value() { return t_[index_]; }
};
int main() {
using Array = std::array<int, 2>;
// The block below works
{
Array array{0, 0};
View<Array> view(array, 0);
view.value() = 5;
assert(array[0] == 5);
}
// The block below gives a compilation error
{
const Array array{5, 5};
View<const Array> view(array, 0);
assert(view.value() == 5);
}
}
If you give the View
a const Array
you also have to specify a const Array
as template argument.
But then returning a non-const
reference with value()
doesn't work anymore, so we disable this function with SFINAE, if the array type is const
.
PS: You wouldn't have the last problem if your class named View
were indeed what one would expect under a view, i.e. non-modifiying and not even having a method returning a non-const
reference.
Upvotes: 5