Created
November 16, 2020 16:50
-
-
Save derrickturk/ae7f5a9909dd3aeee5122fdf09e7492d to your computer and use it in GitHub Desktop.
abstracting over const, four ways
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// this is annoying in every language with a const-like | |
#include <cstddef> | |
#include <iostream> | |
#include <stdexcept> | |
#include <type_traits> | |
// just duplicate... | |
class A { | |
int xs_[10] = { }; | |
public: | |
#define OP_BODY { \ | |
if (i > 10) \ | |
throw std::out_of_range("this one doesn't go to 11"); \ | |
return xs_[i]; \ | |
} | |
int& operator[](std::size_t i) | |
OP_BODY | |
const int& operator[](std::size_t i) const | |
OP_BODY | |
#undef OP_BODY | |
}; | |
// const_cast... | |
class B { | |
int xs_[10] = { }; | |
public: | |
int& operator[](std::size_t i) | |
{ | |
return const_cast<int&>(const_cast<const B&>(*this)[i]); | |
} | |
const int& operator[](std::size_t i) const | |
{ | |
if (i > 10) | |
throw std::out_of_range("this one doesn't go to 11"); | |
return xs_[i]; | |
} | |
}; | |
// a static template helper | |
class C { | |
int xs_[10] = { }; | |
template<class This> | |
requires std::is_same_v<std::remove_const_t<This>, C> | |
static decltype(auto) at(This& self, std::size_t i) | |
{ | |
return self.xs_[i]; | |
} | |
public: | |
int& operator[](std::size_t i) | |
{ | |
return at(*this, i); | |
} | |
const int& operator[](std::size_t i) const | |
{ | |
return at(*this, i); | |
} | |
}; | |
// a hidden friend! (this one handles all const, volatile, &, &&) | |
class D { | |
int xs_[10] = { }; | |
// remember, a friend isn't "private" or "public" - ADL will find this guy | |
template<class This> | |
requires std::is_same_v<std::remove_cvref_t<This>, D> | |
friend decltype(auto) at(This&& self, std::size_t i) | |
{ | |
return static_cast<This&&>(self).xs_[i]; | |
} | |
public: | |
int& operator[](std::size_t i) | |
{ | |
return at(*this, i); | |
} | |
const int& operator[](std::size_t i) const | |
{ | |
return at(*this, i); | |
} | |
}; | |
template<std::size_t N, class T> | |
void print_each(const T& collection) | |
{ | |
auto sep = ""; | |
for (std::size_t i = 0; i < N; ++i) { | |
std::cout << sep << collection[i]; | |
sep = ", "; | |
} | |
std::cout << '\n'; | |
} | |
int main() | |
{ | |
A a; | |
a[3] = 7; | |
a[4] = 5; | |
print_each<10>(a); | |
B b; | |
b[7] = 3; | |
b[5] = 4; | |
print_each<10>(b); | |
C c; | |
c[1] = 3; | |
c[2] = 8; | |
print_each<10>(c); | |
D d; | |
d[8] = 2; | |
d[9] = 1; | |
print_each<10>(d); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment