Reputation: 57
I wrote this code using 2d Vector and Array. But I wanted to use std::array
this time and my code did not work because this was the first time I use std::array
and template.
It gave me for this line:
array<array<int, sizeY>, sizeX> arr;
this error:
Error C2971
std::array
: template parameter_Size
:sizeY,sizeX
: a variable with non-static storage duration cannot be used as a non-type argument
#include <iostream>
#include <array>
using namespace std;
template <size_t Y, size_t X>
bool IsMagicSquare(array<array<int, Y>, X>& ar)
{
int x = ar.size();
int y = ar[0].size();
if (x == y)
{
int ver[x] = { };
int hor[y] = { };
int cross0 = 0;
int cross1 = 0;
for (int i = 0; i < x; i++)
{
for (int j = 0; j < y; j++)
{
hor[i] += ar[i][j];
ver[j] += ar[i][j];
if (i == j)
cross0 += ar[i][j];
if (i + j == x - 1)
cross1 += ar[i][j];
}
}
if (cross0 != cross1)
return false;
else
{
for (int i = 0; i < x; i++)
if ((cross0 != ver[i]) || (cross1 != hor[i]))
return false;
}
}
else
return false;
return true;
}
int main()
{
int sizeX, sizeY;
cout << "Size of Matrix:";
cin >> sizeX >> sizeY;
**array<array<int, sizeY>, sizeX> arr;**
cout << "Elements of the Matrix:";
for (int i = 0; i < sizeX; i++)
for (int j = 0; j < sizeY; j++)
cin >> arr[i][j];
if (IsMagicSquare(arr))
{
for (int i = 0; i < sizeX; i++)
{
cout << "\n";
for (int j = 0; j < sizeY; j++)
cout << arr[i][j];
}
}
else
cout << "Matrix is not magical square!";
return 0;
}
Upvotes: 0
Views: 711
Reputation: 16156
For reference, here's how you can get a std::array
with a size which is decided at runtime:
#include <array>
#include <cstddef>
#include <iostream>
#include <memory>
template<typename T>
struct DynArray {
virtual std::size_t size() const = 0;
virtual T * data() = 0;
virtual ~DynArray() {}
};
template<typename T, std::size_t Size>
struct DynArrayImpl : public DynArray<T> {
std::array<T, Size> array;
std::size_t size() const override {
return array.size();
}
T * data() override {
return array.data();
}
};
template<typename T, std::size_t Size>
struct DynArrayFactory {
static DynArray<T> * allocate(std::size_t const size) {
if (size > Size) {
// ERROR
return nullptr;
}
if (size == Size) {
return new DynArrayImpl<T, Size>();
}
return DynArrayFactory<T, Size - 1>::allocate(size);
}
};
template<typename T>
struct DynArrayFactory<T, 0> {
static DynArray<T> * allocate(std::size_t const size) {
if (size > 0) {
return nullptr;
}
return new DynArrayImpl<T, 0>();
}
};
int main() {
std::size_t size;
std::cin >> size;
std::unique_ptr<DynArray<int>> array{DynArrayFactory<int, 100>::allocate(size)};
std::cout << array->size() << std::endl;
}
This requires a maximum size (100 in this case) to be specified at compile time and is a really convoluted way of doing things; thus not recommended.
Accessing the std::array
is nearly impossible though, unless with similar templated code which then generates code for each possible size (see below). This will generate a lot of code. One can easily access the contents of the array however, as seen in the example above. But really: use std::vector
.
"similar templated code":
template<std::size_t Size>
struct FillWithNumbers {
static void run(std::array<int, Size> & array) {
int n = 0;
std::generate(begin(array), end(array), [&n](){ return n++; });
}
};
template<typename T, std::size_t Size>
struct DynArrayApply {
template<template<std::size_t S> class Fn>
static void apply(DynArray<T> & array) {
if (array.size() > Size) {
// ERROR
}
if (array.size() == Size) {
DynArrayImpl<T, Size> & real = dynamic_cast<DynArrayImpl<T, Size> &>(array);
Fn<Size>::run(real.array);
}
else {
DynArrayApply<T, Size - 1>::template apply<Fn>(array);
}
}
};
template<typename T>
struct DynArrayApply<T,0> {
template<template<std::size_t S> class Fn>
static void apply(DynArray<T> & array) {
if (array.size() > 0) {
// ERROR
}
DynArrayImpl<T, 0> & real = dynamic_cast<DynArrayImpl<T, 0> &>(array);
Fn<0>::run(real.array);
}
};
int main() {
std::size_t size;
std::cin >> size;
std::unique_ptr<DynArray<int>> array{DynArrayFactory<int, 100>::allocate(size)};
DynArrayApply<int, 100>::apply<FillWithNumbers>(*array);
std::cout << array->size() << std::endl;
std::cout << array->data()[array->size() / 2] << std::endl;
}
Upvotes: 2
Reputation: 16843
I wrote this code using 2d Vector and Array.
That is appropriate, as you do not know the size of the matrix until run time.
But I wanted to use
std::array
this time [...]
Well, that's a problem because the size of a std::array
must be known at compile time. Moving away from C-style arrays is a recommended move, but you have to know where to go. Use the correct tool for the job at hand.
Fixed-size arrays: For arrays whose size is known by the compiler, a std::array
is a reasonable replacement. In fact, the std::array
is probably nothing more than the C-style array with a different interface.
Variable-size arrays: For arrays whose size is not known until run time, a std::vector
is a reasonable replacement. Even though the name does not say "array", it is an array. It is a bit more complex than std::array
, but that is because it supports sizes not known at compile time.
This distinction tends to be better-known by those not using gcc, as that compiler has an extension that supports declaring variable-size C-style arrays using the same syntax as declaring fixed-size C-style arrays. It is standard C++ to declare an array along the lines of int col[10]
. However, it is not standard C++ to declare an array along the lines of int col[sizeY]
, where sizeY
has a value supplied at run time. The latter syntax is supported by gcc as an extension, and some people use it without realizing it is an extension (ported from gcc's C support). To some extent, std::vector
makes this extension available in a more portable form.
Upvotes: 1
Reputation: 40842
The size of an array (or template arguments in general) has to be known at compile-time, so there is no way to use the runtime values sizeX
, sizeY
as size (template argument) for an array.
You have to use a variable-length container like std::vector
instead.
Upvotes: 3