Skip to content

Instantly share code, notes, and snippets.

@derrickturk
Created November 16, 2020 16:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save derrickturk/ae7f5a9909dd3aeee5122fdf09e7492d to your computer and use it in GitHub Desktop.
Save derrickturk/ae7f5a9909dd3aeee5122fdf09e7492d to your computer and use it in GitHub Desktop.
abstracting over const, four ways
// 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