2D counterpart of std::array in C++17
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;
$begingroup$
I implemented a 2D counterpart of std::array
named array2d
in C++17. It is an aggregate like std::array
, and provides similar interface. The goal is that if you know how to use std::array
, then you will find yourself at home using array2d
. Any comments are welcome :) For better viewing experience with highlighting, you can refer to this GitHub page.
#include <cstddef>
#include <array>
#include <iterator>
template <typename T, std::size_t N0, std::size_t N1>
struct array2d
using row_t = std::array<T, N1>;
inline static constexpr std::array sizes N0, N1 ;
static constexpr std::size_t size() noexcept return N0 * N1;
static constexpr bool empty() noexcept return !size();
T& at(std::size_t i, std::size_t j) return data_.at(i).at(j);
const T& at(std::size_t i, std::size_t j) const return data_.at(i).at(j);
row_t& operator(std::size_t i) noexcept return data_[i];
const row_t& operator(std::size_t i) const noexcept return data_[i];
T& front() return data_.front().front();
const T& front() const return data_.front().front();
T& back() return data_.back().back();
const T& back() const return data_.back().back();
T* data() noexcept return data_.data()->data();
const T* data() const noexcept return data_.data()->data();
T* begin() noexcept return data();
const T* begin() const noexcept return data();
T* end() noexcept return data() + size();
const T* end() const noexcept return data() + size();
auto rbegin() noexcept return std::make_reverse_iterator(end());
auto rbegin() const noexcept return std::make_reverse_iterator(end());
auto rend() noexcept return std::make_reverse_iterator(begin());
auto rend() const noexcept return std::make_reverse_iterator(begin());
void fill(const T& v)
for (auto& row : data_)
row.fill(v);
friend void swap(array2d& a, array2d& b) a.data_.swap(b.data_);
std::array<row_t, N0> data_;
;
c++ library template-meta-programming c++17
$endgroup$
add a comment |
$begingroup$
I implemented a 2D counterpart of std::array
named array2d
in C++17. It is an aggregate like std::array
, and provides similar interface. The goal is that if you know how to use std::array
, then you will find yourself at home using array2d
. Any comments are welcome :) For better viewing experience with highlighting, you can refer to this GitHub page.
#include <cstddef>
#include <array>
#include <iterator>
template <typename T, std::size_t N0, std::size_t N1>
struct array2d
using row_t = std::array<T, N1>;
inline static constexpr std::array sizes N0, N1 ;
static constexpr std::size_t size() noexcept return N0 * N1;
static constexpr bool empty() noexcept return !size();
T& at(std::size_t i, std::size_t j) return data_.at(i).at(j);
const T& at(std::size_t i, std::size_t j) const return data_.at(i).at(j);
row_t& operator(std::size_t i) noexcept return data_[i];
const row_t& operator(std::size_t i) const noexcept return data_[i];
T& front() return data_.front().front();
const T& front() const return data_.front().front();
T& back() return data_.back().back();
const T& back() const return data_.back().back();
T* data() noexcept return data_.data()->data();
const T* data() const noexcept return data_.data()->data();
T* begin() noexcept return data();
const T* begin() const noexcept return data();
T* end() noexcept return data() + size();
const T* end() const noexcept return data() + size();
auto rbegin() noexcept return std::make_reverse_iterator(end());
auto rbegin() const noexcept return std::make_reverse_iterator(end());
auto rend() noexcept return std::make_reverse_iterator(begin());
auto rend() const noexcept return std::make_reverse_iterator(begin());
void fill(const T& v)
for (auto& row : data_)
row.fill(v);
friend void swap(array2d& a, array2d& b) a.data_.swap(b.data_);
std::array<row_t, N0> data_;
;
c++ library template-meta-programming c++17
$endgroup$
add a comment |
$begingroup$
I implemented a 2D counterpart of std::array
named array2d
in C++17. It is an aggregate like std::array
, and provides similar interface. The goal is that if you know how to use std::array
, then you will find yourself at home using array2d
. Any comments are welcome :) For better viewing experience with highlighting, you can refer to this GitHub page.
#include <cstddef>
#include <array>
#include <iterator>
template <typename T, std::size_t N0, std::size_t N1>
struct array2d
using row_t = std::array<T, N1>;
inline static constexpr std::array sizes N0, N1 ;
static constexpr std::size_t size() noexcept return N0 * N1;
static constexpr bool empty() noexcept return !size();
T& at(std::size_t i, std::size_t j) return data_.at(i).at(j);
const T& at(std::size_t i, std::size_t j) const return data_.at(i).at(j);
row_t& operator(std::size_t i) noexcept return data_[i];
const row_t& operator(std::size_t i) const noexcept return data_[i];
T& front() return data_.front().front();
const T& front() const return data_.front().front();
T& back() return data_.back().back();
const T& back() const return data_.back().back();
T* data() noexcept return data_.data()->data();
const T* data() const noexcept return data_.data()->data();
T* begin() noexcept return data();
const T* begin() const noexcept return data();
T* end() noexcept return data() + size();
const T* end() const noexcept return data() + size();
auto rbegin() noexcept return std::make_reverse_iterator(end());
auto rbegin() const noexcept return std::make_reverse_iterator(end());
auto rend() noexcept return std::make_reverse_iterator(begin());
auto rend() const noexcept return std::make_reverse_iterator(begin());
void fill(const T& v)
for (auto& row : data_)
row.fill(v);
friend void swap(array2d& a, array2d& b) a.data_.swap(b.data_);
std::array<row_t, N0> data_;
;
c++ library template-meta-programming c++17
$endgroup$
I implemented a 2D counterpart of std::array
named array2d
in C++17. It is an aggregate like std::array
, and provides similar interface. The goal is that if you know how to use std::array
, then you will find yourself at home using array2d
. Any comments are welcome :) For better viewing experience with highlighting, you can refer to this GitHub page.
#include <cstddef>
#include <array>
#include <iterator>
template <typename T, std::size_t N0, std::size_t N1>
struct array2d
using row_t = std::array<T, N1>;
inline static constexpr std::array sizes N0, N1 ;
static constexpr std::size_t size() noexcept return N0 * N1;
static constexpr bool empty() noexcept return !size();
T& at(std::size_t i, std::size_t j) return data_.at(i).at(j);
const T& at(std::size_t i, std::size_t j) const return data_.at(i).at(j);
row_t& operator(std::size_t i) noexcept return data_[i];
const row_t& operator(std::size_t i) const noexcept return data_[i];
T& front() return data_.front().front();
const T& front() const return data_.front().front();
T& back() return data_.back().back();
const T& back() const return data_.back().back();
T* data() noexcept return data_.data()->data();
const T* data() const noexcept return data_.data()->data();
T* begin() noexcept return data();
const T* begin() const noexcept return data();
T* end() noexcept return data() + size();
const T* end() const noexcept return data() + size();
auto rbegin() noexcept return std::make_reverse_iterator(end());
auto rbegin() const noexcept return std::make_reverse_iterator(end());
auto rend() noexcept return std::make_reverse_iterator(begin());
auto rend() const noexcept return std::make_reverse_iterator(begin());
void fill(const T& v)
for (auto& row : data_)
row.fill(v);
friend void swap(array2d& a, array2d& b) a.data_.swap(b.data_);
std::array<row_t, N0> data_;
;
c++ library template-meta-programming c++17
c++ library template-meta-programming c++17
asked Mar 14 at 6:52
LingxiLingxi
466215
466215
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
$begingroup$
Let me collect a couple of thoughts here.
Aggregate initialization currently works like this:
array2d<int, 2, 2> a1, 2, 3, 4;
but wouldn't it be favorable to allow for
array2d<int, 2, 2> a1, 2, 3, 4;
std::array::at performs bound checking and throws upon an out of bounds index. When your intention is to stick with the
std::array
interface, you should do the same.If you want the container to be standard-compliant, there are some type aliases missing and maybe more. In particular, there are no
cbegin()
,cend()
,crbegin()
,crend()
member functions. Is this intended?You implicitly use row-major order. Are you sure everyone expects this? Users familiar with Eigen and their fixed size matrices might at least want to customize row-/column-major ordering, e.g.
Eigen::Matrix<int, 2, 2, Eigen::ColMajor> m;
A range based for loop will considerably differ from a manual loop over rows and columns. Example:
// Loop over elements, transposed access. Requires nested loop.
for (std::size_t i = 0; i < 2; ++i)
for (std::size_t j = 0; j < 2; ++j)
std::cout << a[j][i] << "n";
// Loop over elements, tranposed access impossible. Only one loop.
for (const auto& i : d)
std::cout << i << "n";This is slightly unintuitive. Shouldn't the range based for loop require a nested loop as well?
The static data member
sizes
is not used anywhere.
Getting a two-dimensional array to work is not that much of an effort. Getting the semantics right is hard. Sticking to the std::array
interface is a good goal when ease of use is intended for those familiar with the std::array
template. But the additional dimension pulls in requirements that can't be tackled with the concepts of std::array
. I would recommend having a look at established linear algebra libraries and their fixed size matrices. Also, the mdspan proposal for a multi-dimensional view on array types might be a good read.
$endgroup$
$begingroup$
Thanks for reviewing my code. 1) You cana1, 2, 3, 4
and make a new line as you see fit. 2)array2d::at
does bounds checking too, forarray::at
is called under the hood ^_^ 3) You are right they are missing. I think they are tedious and not very useful in practice. But again, thearray2d
is not very useful either XD 4) It is by design that the layout aligns with built-in two-dimensional array. 5) I intend the loop to be similar to what it does witharray
. User needs to use other interface if different traversal is desired. 6)sizes
is part of the interface.
$endgroup$
– Lingxi
Mar 14 at 11:16
$begingroup$
array2d
is not meant to model matrix in linear algebra. Just likearray
andvector
are not meant to model vector in linear algebra. By design, it's only meant to serve the role of a basic fixed-size 2D container. Hopefully more convenient to use than built-in 2D array and nestedarray
.
$endgroup$
– Lingxi
Mar 14 at 11:16
$begingroup$
You're right with the bounds checking of course :) Also, the point thatarray2d
is not meant to be used as a linear algebra vocabulary type is obviously valid. I do see two issues with that, though: if you introducearray2d
to a code base, developers might use it for linear algebra despite the fact that you didn't design it to fit these requirements. And, I personally use two-dimensional arrays for linear algebra and nothing else. If I need more that one dimension, I often find other data structures nearer to my intention.
$endgroup$
– lubgr
Mar 14 at 11:28
add a comment |
$begingroup$
Looks good! Great job.
To initialize the array completely I have to write:
array2d<int, 2, 2> Array1, 2, 2, 3;
The two extra sets of braces are horrible! If you instead have a
T
data member one layer of braces falls of and you need only one set of braces just likestd::array
.array2d<int, 2, 2> Array1, 2, 2, 3; // manageable
Whatever happened to
constexpr
all the things? :)Nested
std::array
s are not guaranteed to be continuous (see this post), although in practice they probably are. Resolving point 1) also fixes this issue.IMO a
at
member that takes only one index and returns a row would make sense for consistency with youroperator
.Consider adding the various member types that a Container is supposed to have (and also the other requirements,
cr[begin, end]
,max_size
, memberswap
, ...).I mean sure,
size
andempty
can bestatic
, but really, conceptually this doesn't make much sense.std::array
'sempty
andsize
are not static too.How about providing various customization points of
std::get
,std::tuple_size
, ... so that your array works with structured bindings.You didn't add any relational operators. Is this intentional?
$endgroup$
$begingroup$
Thanks for reviewing my code, Rakete. 1) Since C++14, you can simplyArray1, 2, 4, 5
without any nested braces. 2) You are right they are missing. It's tedious and a burden, and I don't think they are very useful in practice. So I don't bother :/ 3) Good catch. Today I learned. 4) On a second thought, agreed. We can haveat
overloads that take 1 and 2 indices ^_^ 5) Yes. For serious production code, they should be present. The boring part of writing C++ library code XD
$endgroup$
– Lingxi
Mar 15 at 1:56
$begingroup$
6) User can still invoke them the way as if they are non-static likea.size()
. Making themstatic
provides more possibilities, and removes the need to passthis
. 7) You are right. 8) Not untiloperator<=>
is practically supported by the compilers :P
$endgroup$
– Lingxi
Mar 15 at 2:01
$begingroup$
@Lingxi 1) How did I not know that, thanks :) 2) you really should, it's only one keyword ;) 6) yeah, but still thinks it's weird. 8) that would require that T also has an operator<=>. If it has the traditional operators, then you won't be able to compare the array since operator<=> can't dispatch to the individual relational operators of T.
$endgroup$
– Rakete1111
Mar 15 at 9:04
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "196"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f215399%2f2d-counterpart-of-stdarray-in-c17%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
$begingroup$
Let me collect a couple of thoughts here.
Aggregate initialization currently works like this:
array2d<int, 2, 2> a1, 2, 3, 4;
but wouldn't it be favorable to allow for
array2d<int, 2, 2> a1, 2, 3, 4;
std::array::at performs bound checking and throws upon an out of bounds index. When your intention is to stick with the
std::array
interface, you should do the same.If you want the container to be standard-compliant, there are some type aliases missing and maybe more. In particular, there are no
cbegin()
,cend()
,crbegin()
,crend()
member functions. Is this intended?You implicitly use row-major order. Are you sure everyone expects this? Users familiar with Eigen and their fixed size matrices might at least want to customize row-/column-major ordering, e.g.
Eigen::Matrix<int, 2, 2, Eigen::ColMajor> m;
A range based for loop will considerably differ from a manual loop over rows and columns. Example:
// Loop over elements, transposed access. Requires nested loop.
for (std::size_t i = 0; i < 2; ++i)
for (std::size_t j = 0; j < 2; ++j)
std::cout << a[j][i] << "n";
// Loop over elements, tranposed access impossible. Only one loop.
for (const auto& i : d)
std::cout << i << "n";This is slightly unintuitive. Shouldn't the range based for loop require a nested loop as well?
The static data member
sizes
is not used anywhere.
Getting a two-dimensional array to work is not that much of an effort. Getting the semantics right is hard. Sticking to the std::array
interface is a good goal when ease of use is intended for those familiar with the std::array
template. But the additional dimension pulls in requirements that can't be tackled with the concepts of std::array
. I would recommend having a look at established linear algebra libraries and their fixed size matrices. Also, the mdspan proposal for a multi-dimensional view on array types might be a good read.
$endgroup$
$begingroup$
Thanks for reviewing my code. 1) You cana1, 2, 3, 4
and make a new line as you see fit. 2)array2d::at
does bounds checking too, forarray::at
is called under the hood ^_^ 3) You are right they are missing. I think they are tedious and not very useful in practice. But again, thearray2d
is not very useful either XD 4) It is by design that the layout aligns with built-in two-dimensional array. 5) I intend the loop to be similar to what it does witharray
. User needs to use other interface if different traversal is desired. 6)sizes
is part of the interface.
$endgroup$
– Lingxi
Mar 14 at 11:16
$begingroup$
array2d
is not meant to model matrix in linear algebra. Just likearray
andvector
are not meant to model vector in linear algebra. By design, it's only meant to serve the role of a basic fixed-size 2D container. Hopefully more convenient to use than built-in 2D array and nestedarray
.
$endgroup$
– Lingxi
Mar 14 at 11:16
$begingroup$
You're right with the bounds checking of course :) Also, the point thatarray2d
is not meant to be used as a linear algebra vocabulary type is obviously valid. I do see two issues with that, though: if you introducearray2d
to a code base, developers might use it for linear algebra despite the fact that you didn't design it to fit these requirements. And, I personally use two-dimensional arrays for linear algebra and nothing else. If I need more that one dimension, I often find other data structures nearer to my intention.
$endgroup$
– lubgr
Mar 14 at 11:28
add a comment |
$begingroup$
Let me collect a couple of thoughts here.
Aggregate initialization currently works like this:
array2d<int, 2, 2> a1, 2, 3, 4;
but wouldn't it be favorable to allow for
array2d<int, 2, 2> a1, 2, 3, 4;
std::array::at performs bound checking and throws upon an out of bounds index. When your intention is to stick with the
std::array
interface, you should do the same.If you want the container to be standard-compliant, there are some type aliases missing and maybe more. In particular, there are no
cbegin()
,cend()
,crbegin()
,crend()
member functions. Is this intended?You implicitly use row-major order. Are you sure everyone expects this? Users familiar with Eigen and their fixed size matrices might at least want to customize row-/column-major ordering, e.g.
Eigen::Matrix<int, 2, 2, Eigen::ColMajor> m;
A range based for loop will considerably differ from a manual loop over rows and columns. Example:
// Loop over elements, transposed access. Requires nested loop.
for (std::size_t i = 0; i < 2; ++i)
for (std::size_t j = 0; j < 2; ++j)
std::cout << a[j][i] << "n";
// Loop over elements, tranposed access impossible. Only one loop.
for (const auto& i : d)
std::cout << i << "n";This is slightly unintuitive. Shouldn't the range based for loop require a nested loop as well?
The static data member
sizes
is not used anywhere.
Getting a two-dimensional array to work is not that much of an effort. Getting the semantics right is hard. Sticking to the std::array
interface is a good goal when ease of use is intended for those familiar with the std::array
template. But the additional dimension pulls in requirements that can't be tackled with the concepts of std::array
. I would recommend having a look at established linear algebra libraries and their fixed size matrices. Also, the mdspan proposal for a multi-dimensional view on array types might be a good read.
$endgroup$
$begingroup$
Thanks for reviewing my code. 1) You cana1, 2, 3, 4
and make a new line as you see fit. 2)array2d::at
does bounds checking too, forarray::at
is called under the hood ^_^ 3) You are right they are missing. I think they are tedious and not very useful in practice. But again, thearray2d
is not very useful either XD 4) It is by design that the layout aligns with built-in two-dimensional array. 5) I intend the loop to be similar to what it does witharray
. User needs to use other interface if different traversal is desired. 6)sizes
is part of the interface.
$endgroup$
– Lingxi
Mar 14 at 11:16
$begingroup$
array2d
is not meant to model matrix in linear algebra. Just likearray
andvector
are not meant to model vector in linear algebra. By design, it's only meant to serve the role of a basic fixed-size 2D container. Hopefully more convenient to use than built-in 2D array and nestedarray
.
$endgroup$
– Lingxi
Mar 14 at 11:16
$begingroup$
You're right with the bounds checking of course :) Also, the point thatarray2d
is not meant to be used as a linear algebra vocabulary type is obviously valid. I do see two issues with that, though: if you introducearray2d
to a code base, developers might use it for linear algebra despite the fact that you didn't design it to fit these requirements. And, I personally use two-dimensional arrays for linear algebra and nothing else. If I need more that one dimension, I often find other data structures nearer to my intention.
$endgroup$
– lubgr
Mar 14 at 11:28
add a comment |
$begingroup$
Let me collect a couple of thoughts here.
Aggregate initialization currently works like this:
array2d<int, 2, 2> a1, 2, 3, 4;
but wouldn't it be favorable to allow for
array2d<int, 2, 2> a1, 2, 3, 4;
std::array::at performs bound checking and throws upon an out of bounds index. When your intention is to stick with the
std::array
interface, you should do the same.If you want the container to be standard-compliant, there are some type aliases missing and maybe more. In particular, there are no
cbegin()
,cend()
,crbegin()
,crend()
member functions. Is this intended?You implicitly use row-major order. Are you sure everyone expects this? Users familiar with Eigen and their fixed size matrices might at least want to customize row-/column-major ordering, e.g.
Eigen::Matrix<int, 2, 2, Eigen::ColMajor> m;
A range based for loop will considerably differ from a manual loop over rows and columns. Example:
// Loop over elements, transposed access. Requires nested loop.
for (std::size_t i = 0; i < 2; ++i)
for (std::size_t j = 0; j < 2; ++j)
std::cout << a[j][i] << "n";
// Loop over elements, tranposed access impossible. Only one loop.
for (const auto& i : d)
std::cout << i << "n";This is slightly unintuitive. Shouldn't the range based for loop require a nested loop as well?
The static data member
sizes
is not used anywhere.
Getting a two-dimensional array to work is not that much of an effort. Getting the semantics right is hard. Sticking to the std::array
interface is a good goal when ease of use is intended for those familiar with the std::array
template. But the additional dimension pulls in requirements that can't be tackled with the concepts of std::array
. I would recommend having a look at established linear algebra libraries and their fixed size matrices. Also, the mdspan proposal for a multi-dimensional view on array types might be a good read.
$endgroup$
Let me collect a couple of thoughts here.
Aggregate initialization currently works like this:
array2d<int, 2, 2> a1, 2, 3, 4;
but wouldn't it be favorable to allow for
array2d<int, 2, 2> a1, 2, 3, 4;
std::array::at performs bound checking and throws upon an out of bounds index. When your intention is to stick with the
std::array
interface, you should do the same.If you want the container to be standard-compliant, there are some type aliases missing and maybe more. In particular, there are no
cbegin()
,cend()
,crbegin()
,crend()
member functions. Is this intended?You implicitly use row-major order. Are you sure everyone expects this? Users familiar with Eigen and their fixed size matrices might at least want to customize row-/column-major ordering, e.g.
Eigen::Matrix<int, 2, 2, Eigen::ColMajor> m;
A range based for loop will considerably differ from a manual loop over rows and columns. Example:
// Loop over elements, transposed access. Requires nested loop.
for (std::size_t i = 0; i < 2; ++i)
for (std::size_t j = 0; j < 2; ++j)
std::cout << a[j][i] << "n";
// Loop over elements, tranposed access impossible. Only one loop.
for (const auto& i : d)
std::cout << i << "n";This is slightly unintuitive. Shouldn't the range based for loop require a nested loop as well?
The static data member
sizes
is not used anywhere.
Getting a two-dimensional array to work is not that much of an effort. Getting the semantics right is hard. Sticking to the std::array
interface is a good goal when ease of use is intended for those familiar with the std::array
template. But the additional dimension pulls in requirements that can't be tackled with the concepts of std::array
. I would recommend having a look at established linear algebra libraries and their fixed size matrices. Also, the mdspan proposal for a multi-dimensional view on array types might be a good read.
edited Mar 14 at 10:00
answered Mar 14 at 8:36
lubgrlubgr
6789
6789
$begingroup$
Thanks for reviewing my code. 1) You cana1, 2, 3, 4
and make a new line as you see fit. 2)array2d::at
does bounds checking too, forarray::at
is called under the hood ^_^ 3) You are right they are missing. I think they are tedious and not very useful in practice. But again, thearray2d
is not very useful either XD 4) It is by design that the layout aligns with built-in two-dimensional array. 5) I intend the loop to be similar to what it does witharray
. User needs to use other interface if different traversal is desired. 6)sizes
is part of the interface.
$endgroup$
– Lingxi
Mar 14 at 11:16
$begingroup$
array2d
is not meant to model matrix in linear algebra. Just likearray
andvector
are not meant to model vector in linear algebra. By design, it's only meant to serve the role of a basic fixed-size 2D container. Hopefully more convenient to use than built-in 2D array and nestedarray
.
$endgroup$
– Lingxi
Mar 14 at 11:16
$begingroup$
You're right with the bounds checking of course :) Also, the point thatarray2d
is not meant to be used as a linear algebra vocabulary type is obviously valid. I do see two issues with that, though: if you introducearray2d
to a code base, developers might use it for linear algebra despite the fact that you didn't design it to fit these requirements. And, I personally use two-dimensional arrays for linear algebra and nothing else. If I need more that one dimension, I often find other data structures nearer to my intention.
$endgroup$
– lubgr
Mar 14 at 11:28
add a comment |
$begingroup$
Thanks for reviewing my code. 1) You cana1, 2, 3, 4
and make a new line as you see fit. 2)array2d::at
does bounds checking too, forarray::at
is called under the hood ^_^ 3) You are right they are missing. I think they are tedious and not very useful in practice. But again, thearray2d
is not very useful either XD 4) It is by design that the layout aligns with built-in two-dimensional array. 5) I intend the loop to be similar to what it does witharray
. User needs to use other interface if different traversal is desired. 6)sizes
is part of the interface.
$endgroup$
– Lingxi
Mar 14 at 11:16
$begingroup$
array2d
is not meant to model matrix in linear algebra. Just likearray
andvector
are not meant to model vector in linear algebra. By design, it's only meant to serve the role of a basic fixed-size 2D container. Hopefully more convenient to use than built-in 2D array and nestedarray
.
$endgroup$
– Lingxi
Mar 14 at 11:16
$begingroup$
You're right with the bounds checking of course :) Also, the point thatarray2d
is not meant to be used as a linear algebra vocabulary type is obviously valid. I do see two issues with that, though: if you introducearray2d
to a code base, developers might use it for linear algebra despite the fact that you didn't design it to fit these requirements. And, I personally use two-dimensional arrays for linear algebra and nothing else. If I need more that one dimension, I often find other data structures nearer to my intention.
$endgroup$
– lubgr
Mar 14 at 11:28
$begingroup$
Thanks for reviewing my code. 1) You can
a1, 2, 3, 4
and make a new line as you see fit. 2) array2d::at
does bounds checking too, for array::at
is called under the hood ^_^ 3) You are right they are missing. I think they are tedious and not very useful in practice. But again, the array2d
is not very useful either XD 4) It is by design that the layout aligns with built-in two-dimensional array. 5) I intend the loop to be similar to what it does with array
. User needs to use other interface if different traversal is desired. 6) sizes
is part of the interface.$endgroup$
– Lingxi
Mar 14 at 11:16
$begingroup$
Thanks for reviewing my code. 1) You can
a1, 2, 3, 4
and make a new line as you see fit. 2) array2d::at
does bounds checking too, for array::at
is called under the hood ^_^ 3) You are right they are missing. I think they are tedious and not very useful in practice. But again, the array2d
is not very useful either XD 4) It is by design that the layout aligns with built-in two-dimensional array. 5) I intend the loop to be similar to what it does with array
. User needs to use other interface if different traversal is desired. 6) sizes
is part of the interface.$endgroup$
– Lingxi
Mar 14 at 11:16
$begingroup$
array2d
is not meant to model matrix in linear algebra. Just like array
and vector
are not meant to model vector in linear algebra. By design, it's only meant to serve the role of a basic fixed-size 2D container. Hopefully more convenient to use than built-in 2D array and nested array
.$endgroup$
– Lingxi
Mar 14 at 11:16
$begingroup$
array2d
is not meant to model matrix in linear algebra. Just like array
and vector
are not meant to model vector in linear algebra. By design, it's only meant to serve the role of a basic fixed-size 2D container. Hopefully more convenient to use than built-in 2D array and nested array
.$endgroup$
– Lingxi
Mar 14 at 11:16
$begingroup$
You're right with the bounds checking of course :) Also, the point that
array2d
is not meant to be used as a linear algebra vocabulary type is obviously valid. I do see two issues with that, though: if you introduce array2d
to a code base, developers might use it for linear algebra despite the fact that you didn't design it to fit these requirements. And, I personally use two-dimensional arrays for linear algebra and nothing else. If I need more that one dimension, I often find other data structures nearer to my intention.$endgroup$
– lubgr
Mar 14 at 11:28
$begingroup$
You're right with the bounds checking of course :) Also, the point that
array2d
is not meant to be used as a linear algebra vocabulary type is obviously valid. I do see two issues with that, though: if you introduce array2d
to a code base, developers might use it for linear algebra despite the fact that you didn't design it to fit these requirements. And, I personally use two-dimensional arrays for linear algebra and nothing else. If I need more that one dimension, I often find other data structures nearer to my intention.$endgroup$
– lubgr
Mar 14 at 11:28
add a comment |
$begingroup$
Looks good! Great job.
To initialize the array completely I have to write:
array2d<int, 2, 2> Array1, 2, 2, 3;
The two extra sets of braces are horrible! If you instead have a
T
data member one layer of braces falls of and you need only one set of braces just likestd::array
.array2d<int, 2, 2> Array1, 2, 2, 3; // manageable
Whatever happened to
constexpr
all the things? :)Nested
std::array
s are not guaranteed to be continuous (see this post), although in practice they probably are. Resolving point 1) also fixes this issue.IMO a
at
member that takes only one index and returns a row would make sense for consistency with youroperator
.Consider adding the various member types that a Container is supposed to have (and also the other requirements,
cr[begin, end]
,max_size
, memberswap
, ...).I mean sure,
size
andempty
can bestatic
, but really, conceptually this doesn't make much sense.std::array
'sempty
andsize
are not static too.How about providing various customization points of
std::get
,std::tuple_size
, ... so that your array works with structured bindings.You didn't add any relational operators. Is this intentional?
$endgroup$
$begingroup$
Thanks for reviewing my code, Rakete. 1) Since C++14, you can simplyArray1, 2, 4, 5
without any nested braces. 2) You are right they are missing. It's tedious and a burden, and I don't think they are very useful in practice. So I don't bother :/ 3) Good catch. Today I learned. 4) On a second thought, agreed. We can haveat
overloads that take 1 and 2 indices ^_^ 5) Yes. For serious production code, they should be present. The boring part of writing C++ library code XD
$endgroup$
– Lingxi
Mar 15 at 1:56
$begingroup$
6) User can still invoke them the way as if they are non-static likea.size()
. Making themstatic
provides more possibilities, and removes the need to passthis
. 7) You are right. 8) Not untiloperator<=>
is practically supported by the compilers :P
$endgroup$
– Lingxi
Mar 15 at 2:01
$begingroup$
@Lingxi 1) How did I not know that, thanks :) 2) you really should, it's only one keyword ;) 6) yeah, but still thinks it's weird. 8) that would require that T also has an operator<=>. If it has the traditional operators, then you won't be able to compare the array since operator<=> can't dispatch to the individual relational operators of T.
$endgroup$
– Rakete1111
Mar 15 at 9:04
add a comment |
$begingroup$
Looks good! Great job.
To initialize the array completely I have to write:
array2d<int, 2, 2> Array1, 2, 2, 3;
The two extra sets of braces are horrible! If you instead have a
T
data member one layer of braces falls of and you need only one set of braces just likestd::array
.array2d<int, 2, 2> Array1, 2, 2, 3; // manageable
Whatever happened to
constexpr
all the things? :)Nested
std::array
s are not guaranteed to be continuous (see this post), although in practice they probably are. Resolving point 1) also fixes this issue.IMO a
at
member that takes only one index and returns a row would make sense for consistency with youroperator
.Consider adding the various member types that a Container is supposed to have (and also the other requirements,
cr[begin, end]
,max_size
, memberswap
, ...).I mean sure,
size
andempty
can bestatic
, but really, conceptually this doesn't make much sense.std::array
'sempty
andsize
are not static too.How about providing various customization points of
std::get
,std::tuple_size
, ... so that your array works with structured bindings.You didn't add any relational operators. Is this intentional?
$endgroup$
$begingroup$
Thanks for reviewing my code, Rakete. 1) Since C++14, you can simplyArray1, 2, 4, 5
without any nested braces. 2) You are right they are missing. It's tedious and a burden, and I don't think they are very useful in practice. So I don't bother :/ 3) Good catch. Today I learned. 4) On a second thought, agreed. We can haveat
overloads that take 1 and 2 indices ^_^ 5) Yes. For serious production code, they should be present. The boring part of writing C++ library code XD
$endgroup$
– Lingxi
Mar 15 at 1:56
$begingroup$
6) User can still invoke them the way as if they are non-static likea.size()
. Making themstatic
provides more possibilities, and removes the need to passthis
. 7) You are right. 8) Not untiloperator<=>
is practically supported by the compilers :P
$endgroup$
– Lingxi
Mar 15 at 2:01
$begingroup$
@Lingxi 1) How did I not know that, thanks :) 2) you really should, it's only one keyword ;) 6) yeah, but still thinks it's weird. 8) that would require that T also has an operator<=>. If it has the traditional operators, then you won't be able to compare the array since operator<=> can't dispatch to the individual relational operators of T.
$endgroup$
– Rakete1111
Mar 15 at 9:04
add a comment |
$begingroup$
Looks good! Great job.
To initialize the array completely I have to write:
array2d<int, 2, 2> Array1, 2, 2, 3;
The two extra sets of braces are horrible! If you instead have a
T
data member one layer of braces falls of and you need only one set of braces just likestd::array
.array2d<int, 2, 2> Array1, 2, 2, 3; // manageable
Whatever happened to
constexpr
all the things? :)Nested
std::array
s are not guaranteed to be continuous (see this post), although in practice they probably are. Resolving point 1) also fixes this issue.IMO a
at
member that takes only one index and returns a row would make sense for consistency with youroperator
.Consider adding the various member types that a Container is supposed to have (and also the other requirements,
cr[begin, end]
,max_size
, memberswap
, ...).I mean sure,
size
andempty
can bestatic
, but really, conceptually this doesn't make much sense.std::array
'sempty
andsize
are not static too.How about providing various customization points of
std::get
,std::tuple_size
, ... so that your array works with structured bindings.You didn't add any relational operators. Is this intentional?
$endgroup$
Looks good! Great job.
To initialize the array completely I have to write:
array2d<int, 2, 2> Array1, 2, 2, 3;
The two extra sets of braces are horrible! If you instead have a
T
data member one layer of braces falls of and you need only one set of braces just likestd::array
.array2d<int, 2, 2> Array1, 2, 2, 3; // manageable
Whatever happened to
constexpr
all the things? :)Nested
std::array
s are not guaranteed to be continuous (see this post), although in practice they probably are. Resolving point 1) also fixes this issue.IMO a
at
member that takes only one index and returns a row would make sense for consistency with youroperator
.Consider adding the various member types that a Container is supposed to have (and also the other requirements,
cr[begin, end]
,max_size
, memberswap
, ...).I mean sure,
size
andempty
can bestatic
, but really, conceptually this doesn't make much sense.std::array
'sempty
andsize
are not static too.How about providing various customization points of
std::get
,std::tuple_size
, ... so that your array works with structured bindings.You didn't add any relational operators. Is this intentional?
answered Mar 14 at 22:11
Rakete1111Rakete1111
2,2641822
2,2641822
$begingroup$
Thanks for reviewing my code, Rakete. 1) Since C++14, you can simplyArray1, 2, 4, 5
without any nested braces. 2) You are right they are missing. It's tedious and a burden, and I don't think they are very useful in practice. So I don't bother :/ 3) Good catch. Today I learned. 4) On a second thought, agreed. We can haveat
overloads that take 1 and 2 indices ^_^ 5) Yes. For serious production code, they should be present. The boring part of writing C++ library code XD
$endgroup$
– Lingxi
Mar 15 at 1:56
$begingroup$
6) User can still invoke them the way as if they are non-static likea.size()
. Making themstatic
provides more possibilities, and removes the need to passthis
. 7) You are right. 8) Not untiloperator<=>
is practically supported by the compilers :P
$endgroup$
– Lingxi
Mar 15 at 2:01
$begingroup$
@Lingxi 1) How did I not know that, thanks :) 2) you really should, it's only one keyword ;) 6) yeah, but still thinks it's weird. 8) that would require that T also has an operator<=>. If it has the traditional operators, then you won't be able to compare the array since operator<=> can't dispatch to the individual relational operators of T.
$endgroup$
– Rakete1111
Mar 15 at 9:04
add a comment |
$begingroup$
Thanks for reviewing my code, Rakete. 1) Since C++14, you can simplyArray1, 2, 4, 5
without any nested braces. 2) You are right they are missing. It's tedious and a burden, and I don't think they are very useful in practice. So I don't bother :/ 3) Good catch. Today I learned. 4) On a second thought, agreed. We can haveat
overloads that take 1 and 2 indices ^_^ 5) Yes. For serious production code, they should be present. The boring part of writing C++ library code XD
$endgroup$
– Lingxi
Mar 15 at 1:56
$begingroup$
6) User can still invoke them the way as if they are non-static likea.size()
. Making themstatic
provides more possibilities, and removes the need to passthis
. 7) You are right. 8) Not untiloperator<=>
is practically supported by the compilers :P
$endgroup$
– Lingxi
Mar 15 at 2:01
$begingroup$
@Lingxi 1) How did I not know that, thanks :) 2) you really should, it's only one keyword ;) 6) yeah, but still thinks it's weird. 8) that would require that T also has an operator<=>. If it has the traditional operators, then you won't be able to compare the array since operator<=> can't dispatch to the individual relational operators of T.
$endgroup$
– Rakete1111
Mar 15 at 9:04
$begingroup$
Thanks for reviewing my code, Rakete. 1) Since C++14, you can simply
Array1, 2, 4, 5
without any nested braces. 2) You are right they are missing. It's tedious and a burden, and I don't think they are very useful in practice. So I don't bother :/ 3) Good catch. Today I learned. 4) On a second thought, agreed. We can have at
overloads that take 1 and 2 indices ^_^ 5) Yes. For serious production code, they should be present. The boring part of writing C++ library code XD$endgroup$
– Lingxi
Mar 15 at 1:56
$begingroup$
Thanks for reviewing my code, Rakete. 1) Since C++14, you can simply
Array1, 2, 4, 5
without any nested braces. 2) You are right they are missing. It's tedious and a burden, and I don't think they are very useful in practice. So I don't bother :/ 3) Good catch. Today I learned. 4) On a second thought, agreed. We can have at
overloads that take 1 and 2 indices ^_^ 5) Yes. For serious production code, they should be present. The boring part of writing C++ library code XD$endgroup$
– Lingxi
Mar 15 at 1:56
$begingroup$
6) User can still invoke them the way as if they are non-static like
a.size()
. Making them static
provides more possibilities, and removes the need to pass this
. 7) You are right. 8) Not until operator<=>
is practically supported by the compilers :P$endgroup$
– Lingxi
Mar 15 at 2:01
$begingroup$
6) User can still invoke them the way as if they are non-static like
a.size()
. Making them static
provides more possibilities, and removes the need to pass this
. 7) You are right. 8) Not until operator<=>
is practically supported by the compilers :P$endgroup$
– Lingxi
Mar 15 at 2:01
$begingroup$
@Lingxi 1) How did I not know that, thanks :) 2) you really should, it's only one keyword ;) 6) yeah, but still thinks it's weird. 8) that would require that T also has an operator<=>. If it has the traditional operators, then you won't be able to compare the array since operator<=> can't dispatch to the individual relational operators of T.
$endgroup$
– Rakete1111
Mar 15 at 9:04
$begingroup$
@Lingxi 1) How did I not know that, thanks :) 2) you really should, it's only one keyword ;) 6) yeah, but still thinks it's weird. 8) that would require that T also has an operator<=>. If it has the traditional operators, then you won't be able to compare the array since operator<=> can't dispatch to the individual relational operators of T.
$endgroup$
– Rakete1111
Mar 15 at 9:04
add a comment |
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f215399%2f2d-counterpart-of-stdarray-in-c17%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown