#include <iostream>
#include <memory>
using std::cout;
using std::endl;
template<typename T, int dimension = 1>
class Array
{
private:
std::unique_ptr<T[]> pointer;
int size[dimension];
int realSize;
public:
Array()
{
}
template<typename... Ns>
Array(Ns... ns)
: realSize(1)
{
create(1, ns...);
}
private:
template<typename... Ns>
void create(int d, int n, Ns... ns)
{
realSize *= n;
size[d - 1] = n;
create(d + 1, ns...);
}
void create(int d)
{
pointer = std::unique_ptr<T[]>(new T[realSize]);
}
int computeSubSize(int d) const
{
if (d == dimension)
{
return 1;
}
return size[d] * computeSubSize(d + 1);
}
template<typename... Ns>
int getIndex(int d, int n, Ns... ns) const
{
return n * computeSubSize(d) + getIndex(d + 1, ns...);
}
int getIndex(int d) const
{
return 0;
}
public:
template<typename... Ns>
T& operator()(Ns... ns) const
{
return pointer[getIndex(1, ns...)];
}
int getSize(int d = 1) const
{
return size[d - 1];
}
};
int main()
{
constexpr int N = 10;
Array<int> a(N);
for (int i = 0; i < a.getSize(); ++i)
{
a(i) = i + 1;
cout << a(i) << ' ';
}
cout << '\n' << endl;
Array<int, 2> a2(N, N * 2);
for (int i = 0; i < a2.getSize(1); ++i)
{
for (int j = 0; j < a2.getSize(2); ++j)
{
a2(i, j) = i + j + 2;
if (a2(i, j) < 10)
{
cout << '0';
}
cout << a2(i, j) << ' ';
}
cout << endl;
}
return 0;
}
Output
1 2 3 4 5 6 7 8 9 10 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
3 Answers 3
No need for an empty constructor in C++11:
Array() { }
You can just use a
default
constructor:Array() = default;
It's a little confusing to have multiple
public
/private
sections. Here, you can just put all thepublic
code under the same keyword.You could make your structure more useful by providing iterators. This will, for instance, allow you to use range based
for
-loops instead of plain ones for iterating through this structure.You don't need
std::endl
if you just need newlines. Just output"\n"
instead for this. More info about this can be found here.It's unnecessary to have your own
return 0
at the end ofmain()
in C++. The compiler will provide this return for you.
There are quite a few things :
- Naming your variables. I don't know why, the naming of your functions is quite good, but not the naming of your variables, why ?
a
,n
,i
,d
, among others, deserve to have a real name, for readability. if (a2(i, j) < 10)
I see what you're doing here but please don't do it that way. Usingstd::setfill
andstd::setw
could do that for you. Or a good oldprintf
for (int i = 0; i < a2.getSize(1); ++i)
Is the size of a2 going to change inside the loop ? If not, there's no need to compute at each loop iteration.- Not a single comment in all your code, that's a performance, but not a good one. If you want to make up for this, you could even use Doxygen-style comments, to be able to generate quickly some documentation, in addition to normal comments inside your complicated functions.
cout << '\n' << endl;
Not quite sure what you want to do there.
For your int
template parameter, it makes no sense to have a signed dimension quantity. Use size_t
as that parameter and update int
to size_t
in your code.
int size[dimension];
- isn't this just the number of elements in a single-dimensional array? \$\endgroup\$dimension
here. \$\endgroup\$size[dimension]
is just the number of elements, but in an n-dimensional array where n > 1, it stores the size for each dimension. \$\endgroup\$