Skip to content

Instantly share code, notes, and snippets.

@rmartinho
Created October 26, 2012 17:04
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rmartinho/3959958 to your computer and use it in GitHub Desktop.
Save rmartinho/3959958 to your computer and use it in GitHub Desktop.
Two-dimensional array with dimensions determined at compile-time
// Two-dimensional array with dimensions determined at compile-time
//
// Written in 2012 by Martinho Fernandes
//
// To the extent possible under law, the author(s) have dedicated all copyright and related
// and neighboring rights to this software to the public domain worldwide. This software is
// distributed without any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
// Installation:
// Place this into a header file and #include it in your code. Done.
//
// Usage:
// so::sarray2d<int[10][10]> x; // create a 10x10 array
// so::sarray2d<int[2][2]> y = {{ { 1, 2 }, { 3, 4 } }}; // initialize a 2x2 array (unfortunately it needs three levels of braces)
// int x12 = x[1][2]; // access an element
// x[1][2] = 42; // modify an element
// int* all = x.data(); // get a pointer to the whole array
// int* row1p = x[1].data(); // get a pointer to a row
// std::sort(x.begin(), x.end()); // use the whole array in standard library algorithms
// std::sort(x[1].begin(), x[1].end()); // use a row in standard library algorithms
// so::sarray2d<int[10][10]> copy_of_x = x; // make a copy
//
// This can also be easily and safely returned from functions by value, no need to use pointers or dynamic allocation:
// so::sarray2d<int[2][2]> get_an_array(int x) {
// so::sarray2d<int[2][2]> result = {{ { x*1, x*2 }, { x*3, x*4 } }};
// return result;
// }
//
// Only two-dimensional arrays are supported.
// If you think you need a three-dimensional array, you're probably doing
// it wrong. But if you really want to take a stab at doing so, you may use
// this code as a starting point.
//
// If you don't want any C++11 features #define SO_ARRAY2D_NO_CPP11 before #including.
//
// Now, go forth and stop using multidimensional C arrays!
#ifndef SO_SARRAY2D_HPP_INCLUDED
#define SO_SARRAY2D_HPP_INCLUDED
#include <cassert> // assert
#include <cstddef> // size_t, ptrdiff_t
#ifndef SO_ARRAY2D_NO_CPP11
#define SO_ARRAY2D_CPP11_DELETE = delete
#else
#define SO_ARRAY2D_CPP11_DELETE
#endif
namespace so {
template <typename T>
class sarray2d {
#ifndef SO_ARRAY2D_NO_CPP11
template <typename> struct bad_usage { enum { value = false }; };
static_assert(bad_usage<T>::value, "You can only create an sarray2d with 2 dimensions, like so::sarray2d<int[2][3]>");
#else
struct bad_usage;
bad_usage you_can_only_create_an_sarray2d_with_2_dimensions;
#endif
};
template <typename T, std::size_t N, std::size_t M>
class sarray2d<T[N][M]> {
public:
class proxy {
public:
T& operator[](std::ptrdiff_t index) {
assert(index >= 0 && index < M);
return storage[row][index];
}
T* begin() { return &storage[row][0]; }
T* end() { return &storage[row][0] + M; }
T* data() { return &storage[row][0]; }
private:
template <typename X>
void operator=(X const&) SO_ARRAY2D_CPP11_DELETE;
friend class sarray2d<T[N][M]>;
proxy(T (&storage)[N][M], std::ptrdiff_t row)
: storage(storage), row(row) {}
T (&storage)[N][M];
std::ptrdiff_t row;
};
class const_proxy {
public:
T const& operator[](std::ptrdiff_t index) {
assert(index >= 0 && index < M);
return storage[row][index];
}
T const* begin() const { return &storage[row][0]; }
T const* end() const { return &storage[row][0] + M; }
T const* data() const { return &storage[row][0]; }
private:
template <typename X>
void operator=(X const&) SO_ARRAY2D_CPP11_DELETE;
friend class sarray2d<T[N][M]>;
const_proxy(T const (&storage)[N][M], std::ptrdiff_t row)
: storage(storage), row(row) {}
T const (&storage)[N][M];
std::ptrdiff_t row;
};
proxy operator[](std::ptrdiff_t index) {
assert(index >= 0 && index < N);
return proxy(storage, index);
}
const_proxy operator[](std::ptrdiff_t index) const {
assert(index >= 0 && index < N);
return const_proxy(storage, index);
}
T* begin() { return &storage[0][0]; }
T* end() { return &storage[0][0] + N*M; }
T* data() { return &storage[0][0]; }
T const* begin() const { return &storage[0][0]; }
T const* end() const { return &storage[0][0] + N*M; }
T const* data() const { return &storage[0][0]; }
T storage[N][M]; // public only to facilitate aggregate construction
// do not use directly
};
}
#undef SO_ARRAY2D_CPP11_DELETE
#endif
@rmartinho
Copy link
Author

I wrote this as a simple snippet I can drop on StackOverflow questions from people having trouble getting their multi-dimensional C arrays to work some way or another.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment