Forward declaration of struct with constexpr constructor - c++

I would like to add global instances of a struct class to my program that server special meaning. A MWE that works is
// Example program
#include <iostream>
constexpr int x_max = 3;
constexpr int y_max = 4;
typedef struct Position {
constexpr Position(int x, int y) : x(x), y(y) {};
int x;
int y;
inline bool operator!=(const Position &rhs) const {
return (x != rhs.x || y != rhs.y);
}
inline bool inside_grid(const Position &empty) const {
return (x >= 0 && x < x_max && y >= 0 && y < y_max && *this != empty);
}
} Position;
constexpr Position empty = Position(1,1);
int main()
{
Position p1 = Position(2,3);
Position p2 = Position(1,1);
std::cout << "p1.inside_grid(empty) = " << p1.inside_grid(empty) << " and p2.inside_grid(empty) = " << p2.inside_grid(empty) << std::endl;
}
The global constant empty would have to be passed to every call of method inside_grid which made me think if I could declare the global at the beginning of the program and modify the inside_grid method to not take any parameters like so:
// Example program
#include <iostream>
struct Position;
constexpr Position empty = Point(1, 1);
constexpr int x_max = 3;
constexpr int y_max = 4;
typedef struct Position {
constexpr Position(int x, int y) : x(x), y(y) {};
int x;
int y;
inline bool operator!=(const Position &rhs) const {
return (x != rhs.x || y != rhs.y);
}
inline bool inside_grid() const {
return (x >= 0 && x < x_max && y >= 0 && y < y_max && *this != empty);
}
} Position;
int main()
{
Position p1 = Position(2,3);
Position p2 = Position(1,1);
std::cout << "p1.inside_grid() = " << p1.inside_grid() << " and p2.inside_grid() = " << p2.inside_grid() << std::endl;
}
The problem is that this won't compile due to errors that I cannot really understand:
error: variable 'constexpr const Position empty' has initializer but incomplete type
error: invalid use of incomplete type 'struct Position'
Can this problem be resolved?

You can forward declare your inside_grid() method and define it later, after empty is created:
// Example program
#include <iostream>
struct Position;
constexpr int x_max = 3;
constexpr int y_max = 4;
typedef struct Position {
constexpr Position(int x, int y) : x(x), y(y) {};
int x;
int y;
inline bool operator!=(const Position &rhs) const {
return (x != rhs.x || y != rhs.y);
}
bool inside_grid() const;
} Position;
constexpr Position empty = Position(1, 1);
inline bool Position::inside_grid() const {
return (x >= 0 && x < x_max && y >= 0 && y < y_max && *this != empty);
}
int main()
{
Position p1 = Position(2,3);
Position p2 = Position(1,1);
std::cout << "p1.inside_grid() = " << p1.inside_grid() << " and p2.inside_grid() = " << p2.inside_grid() << std::endl;
}

Related

Question about Dynamic memory allocation in C++ for 3D array

I want to write a fuction to creat a 3D Matrix,but I have a broblem when I try to display it,Please help me,Thanks.
My teacher gave me his codes.His codes can create a 2D array which has Dynamic memory, I want to change his codes to creat a 3D matrix. When I tried to display the Matrix,I realize the array I created is a 2D array,And Because I just begin to use C++,I can't find my mistake.
/*<Array3D.h>*/
#pragma once
#ifndef _ARRAY_3D_H_
#define _ARRAY_3D_H_
//-----------------------------------------
#include <cassert>
#include <vector>
using namespace std;
template<typename T>
class Array3D
{
public:
typedef Array3D<T> _Myt;
Array3D()
: m_nRows(0)
, m_nCols(0)
, m_nDepths(0)
{}
Array3D(size_t r, size_t c,size_t d)
{
Resize(r, c, d);
}
//Allocating memory size
void Resize(size_t r, size_t c,size_t d)
{
if (r == m_nRows && c == m_nCols && d==m_nDepths) { return; }
bool bValid = r > 0 && c > 0 && d>0;
if (!bValid) return;
m_nRows = r;
m_nCols = c;
m_nDepths = d;
m_v.resize(m_nRows * m_nCols * m_nDepths);
}
const T* operator[](size_t r) const
{
assert(r >= 0 && r < m_nRows);
return &(*(m_v.begin() + (r * m_nCols * m_nDepths)));
}
T* operator[](size_t r)
{
assert(r >= 0 && r < m_nRows);
return &(*(m_v.begin() + (r * m_nCols * m_nDepths)));
}
//Gets the start position of a one-dimensional array
const T* GetRawPointer() const { return &(m_v[0]); }
T* GetRawPointer() { return &(m_v[0]); }
long Rows() const
{
return static_cast<long>(m_nRows);
}
long Cols() const
{
return static_cast<long>(m_nCols);
}
long Depths() const
{
return static_cast<long>(m_nDepths);
}
long TotalSize() const
{
return static_cast<long>(m_nRows * m_nCols * m_nDepths);
}
void ClearUp()
{
m_nRows = 0;
m_nCols = 0;
m_nDepths = 0;
m_v.clear();
}
bool IsEmpty() const { return m_v.empty(); }
protected:
vector<T> m_v;// Internally a one-dimensional is used
size_t m_nRows;
size_t m_nCols;
size_t m_nDepths;
};
<Matrix3D.h>
#pragma once
#include "Array3D.h"
class Matrix3D
{
public:
Matrix3D(int r = 0, int c = 0, int d = 0)
{
setSize(r, c, d);
}
void setSize(int r, int c, int d) { m_data3D.Resize(r, c, d); }
void clear() { m_data3D.ClearUp(); }
int rows() const { return m_data3D.Rows(); }
int cols() const { return m_data3D.Cols(); }
int Depths() const { return m_data3D.Depths(); }
void display() const;
//Operator Overloading
float* operator[](int rIndex) { return m_data3D[rIndex]; }
const float* operator[](int rIndex) const { return m_data3D[rIndex]; }
private:
Array3D<float> m_data3D;
};
#include "Matrix3D.h"
#include <iostream>
using namespace std;
void Matrix3D::display() const
{
if (m_data3D.IsEmpty())
{
cout << "empty matrix" << endl;
return;
}
cout << "------------------------" << endl;
const int rows = this->rows();
const int cols = this->cols();
const int Depths = this->Depths();
cout << rows << "x" << cols << "x" << Depths << endl;
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
for(int k = 0 ;k < Depths; k++)
{
cout << m_data3D[i][j][k] << ' '; /*This section will pose an error "E0142"*/
}
cout << endl;
}
}
}
I am going to guess that your teachers class was Array2D and that you mostly just added m_nDepths to it to turn it into Array3D. If this assumption is not right, then my answer here is most likely going to be completely wrong.
But if I am right, then his operator[] looked something like:
T* operator[](size_t r)
{
assert(r >= 0 && r < m_nRows);
return &(*(m_v.begin() + (r * m_nCols)));
}
Which means that when you then do m_data2D[i][j], what happens is that the first [i] applies to the Array2D. This, as shown above, returns a pointer (in your case likely a float*). The [j] is then applied to this pointer, which results in some pointer arithmetic that results in a float (for a float *x; x[y] means *(x+y)).
In other words, your teacher stores his 2D array line by line in a 1D array, and when you [] into it you get a pointer to the right line that you can then further [] into.
This is all fine.
The problem is when you add a third dimension to this and try the same approach: The first [] still returns a float* (but this time to the correct 2D matrix), the second [] returns a float (the first element in the correct line of the 2D matrix), and the third [] tries to apply to a float - which it cannot, and you get the error.
There are two ways to fix this:
Change the return type of Array3D::operator[] to return some kind of 2D array type whose operator[] works like the original Array2D.
Abandon the operator[] approach and replace it with a member function that takes 3 arguments and returns the correct element right away. I think this is what I would prefer myself.
For the second option, something like (not tested, rather large chance I messed up the order of the arguments):
T element(size_t x, size_t y, size_t z) const
{
assert(x >= 0 && x < m_nDepths);
assert(y >= 0 && y < m_nCols);
assert(z >= 0 && z < m_nRows);
return *(m_v.begin() + (x * m_nCols * m_nDepths +
y * m_nCols +
z));
}
T& element(size_t x, size_t y, size_t z)
{
assert(x >= 0 && x < m_nDepths);
assert(y >= 0 && y < m_nCols);
assert(z >= 0 && z < m_nRows);
return *(m_v.begin() + (x * m_nCols * m_nDepths +
y * m_nCols +
z));
}
Which turns cout << m_data3D[i][j][k] << ' '; into cout << m_data3D.element(i,j,k) << ' ';

Finding the total area and cover area of multiple polygon

I'm trying to solve this problem using the slicing technic.
But I just passed the first two test cases in this gym (Problem A)
2017-2018 ACM-ICPC East Central North America Regional Contest (ECNA 2017)
The whole step in my code looks like this:
calculate the total area using vector cross when inputting the polygon information.
find all the endpoints and intersection points, and record x value of them.
for each slice (sort x list and for each interval) find the lines from every polygon which crosses this interval and store this smaller segment.
sort segments.
for each trapezoid or triangle, calculate the area if this area is covered by some polygon.
sum them all to find the cover area.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
template<typename T> using p = pair<T, T>;
template<typename T> using vec = vector<T>;
template<typename T> using deq = deque<T>;
// #define dbg
#define yccc ios_base::sync_with_stdio(false), cin.tie(0)
#define al(a) a.begin(),a.end()
#define F first
#define S second
#define eb emplace_back
const int INF = 0x3f3f3f3f;
const ll llINF = 1e18;
const int MOD = 1e9+7;
const double eps = 1e-9;
const double PI = acos(-1);
double fcmp(double a, double b = 0, double eps = 1e-9) {
if (fabs(a-b) < eps) return 0;
return a - b;
}
template<typename T1, typename T2>
istream& operator>>(istream& in, pair<T1, T2>& a) { in >> a.F >> a.S; return in; }
template<typename T1, typename T2>
ostream& operator<<(ostream& out, pair<T1, T2> a) { out << a.F << ' ' << a.S; return out; }
struct Point {
double x, y;
Point() {}
Point(double x, double y) : x(x), y(y) {}
Point operator+(const Point& src) {
return Point(src.x + x, src.y + y);
}
Point operator-(const Point& src) {
return Point(x - src.x, y - src.y);
}
Point operator*(double src) {
return Point(x * src, y * src);
}
//* vector cross.
double operator^(Point src) {
return x * src.y - y * src.x;
}
};
struct Line {
Point sp, ep;
Line() {}
Line(Point sp, Point ep) : sp(sp), ep(ep) {}
//* check if two segment intersect.
bool is_intersect(Line src) {
if (fcmp(ori(src.sp) * ori(src.ep)) < 0 and fcmp(src.ori(sp) * src.ori(ep)) < 0) {
double t = ((src.ep - src.sp) ^ (sp - src.sp)) / ((ep - sp) ^ (src.ep - src.sp));
return fcmp(t) >= 0 and fcmp(t, 1) <= 0;
}
return false;
}
//* if two segment intersect, find the intersection point.
Point intersect(Line src) {
double t = ((src.ep - src.sp) ^ (sp - src.sp)) / ((ep - sp) ^ (src.ep - src.sp));
return sp + (ep - sp) * t;
}
double ori(Point src) {
return (ep - sp) ^ (src - sp);
}
bool operator<(Line src) const {
if (fcmp(sp.y, src.sp.y) != 0)
return sp.y < src.sp.y;
return ep.y < src.ep.y;
}
};
int next(int i, int n) {
return (i + 1) % n;
}
int main()
{
yccc;
int n;
cin >> n;
//* the point list and the line list of polygons.
vec<vec<Point>> p_list(n);
vec<vec<Line>> l_list(n);
//* x's set for all endpoints and intersection points
vec<double> x_list;
//* initializing point list and line list
double total = 0, cover = 0;
for (int i = 0; i < n; i++) {
int m;
cin >> m;
p_list[i].resize(m);
for (auto &k : p_list[i]) {
cin >> k.x >> k.y;
x_list.eb(k.x);
}
l_list[i].resize(m);
for (int k = 0; k < m; k++) {
l_list[i][k].sp = p_list[i][k];
l_list[i][k].ep = p_list[i][next(k, m)];
}
//* calculate the polygon area.
double tmp = 0;
for (int k = 0; k < m; k++) {
tmp += l_list[i][k].sp.x * l_list[i][k].ep.y - l_list[i][k].sp.y * l_list[i][k].ep.x;
}
total += abs(tmp);
}
//* find all intersection points
for (int i = 0; i < n; i++)
for (int k = i+1; k < n; k++) {
for (auto li : l_list[i])
for (auto lk : l_list[k])
if (li.is_intersect(lk)) {
x_list.eb(li.intersect(lk).x);
}
}
sort(al(x_list));
auto same = [](double a, double b) -> bool {
return fcmp(a, b) == 0;
};
x_list.resize(unique(al(x_list), same) - x_list.begin());
//* for each slicing, calculate the cover area.
for (int i = 0; i < x_list.size() - 1; i++) {
vec<pair<Line, int>> seg;
for (int k = 0; k < n; k++) {
for (auto line : l_list[k]) {
//* check if line crosses this slicing
if (fcmp(x_list[i], min(line.sp.x, line.ep.x)) >= 0 and fcmp(max(line.sp.x, line.ep.x), x_list[i+1]) >= 0) {
Point sub = line.ep - line.sp;
double t_sp = (x_list[i] - line.sp.x) / sub.x, t_ep = (x_list[i+1] - line.sp.x) / sub.x;
seg.eb(Line(Point(x_list[i], line.sp.y + sub.y * t_sp), Point(x_list[i+1], line.sp.y + sub.y * t_ep)), k);
}
}
}
//* sort this slicing
sort(al(seg));
deq<bool> inside(n);
int count = 0;
Line prev;
// cout << x_list[i] << ' ' << x_list[i+1] << endl;
//* calculate cover area in this slicing.
for (int k = 0; k < seg.size(); k++) {
if (count)
cover += ((seg[k].F.sp.y - prev.sp.y) + (seg[k].F.ep.y - prev.ep.y)) * (x_list[i+1] - x_list[i]);
prev = seg[k].F;
// cout << seg[k].S << ": (" << seg[k].F.sp.x << ", " << seg[k].F.sp.y << "), (" << seg[k].F.ep.x << ", " << seg[k].F.ep.y << ")" << endl;
inside[k] = !inside[k];
count += (inside[k] ? 1 : -1);
}
}
//* answer
cout << total / 2 << ' ' << cover / 2;
}
I can't not figure out which part I made a mistake :(

2D Poisson-disk sampling in a specific square (not a unit square) with specific minimum distance

Is there any way I can modify the poisson-disk points generator finding here.I need to generate new poisson points using the coordinates of points in the textfile.txt to improve the distribution. below the c++ code of poisson-disk sampling in a unit square.
poissonGenerator.h:
#include <vector>
#include <random>
#include <stdint.h>
#include <time.h>
namespace PoissoGenerator
{
class DefaultPRNG
{
public:
DefaultPRNG()
: m_Gen(std::random_device()())
, m_Dis(0.0f, 1.f)
{
// prepare PRNG
m_Gen.seed(time(nullptr));
}
explicit DefaultPRNG(unsigned short seed)
: m_Gen(seed)
, m_Dis(0.0f, 1.f)
{
}
double RandomDouble()
{
return static_cast <double>(m_Dis(m_Gen));
}
int RandomInt(int Max)
{
std::uniform_int_distribution<> DisInt(0, Max);
return DisInt(m_Gen);
}
private:
std::mt19937 m_Gen;
std::uniform_real_distribution<double> m_Dis;
};
struct sPoint
{
sPoint()
: x(0)
, y(0)
, m_valid(false){}
sPoint(double X, double Y)
: x(X)
, y(Y)
, m_valid(true){}
double x;
double y;
bool m_valid;
//
bool IsInRectangle() const
{
return x >= 0 && y >= 0 && x <= 1 && y <= 1;
}
//
bool IsInCircle() const
{
double fx = x - 0.5f;
double fy = y - 0.5f;
return (fx*fx + fy*fy) <= 0.25f;
}
};
struct sGridPoint
{
sGridPoint(int X, int Y)
: x(X)
, y(Y)
{}
int x;
int y;
};
double GetDistance(const sPoint& P1, const sPoint& P2)
{
return sqrt((P1.x - P2.x)*(P1.x - P2.x) + (P1.y - P2.y)*(P1.y - P2.y));
}
sGridPoint ImageToGrid(const sPoint& P, double CellSize)
{
return sGridPoint((int)(P.x / CellSize), (int)(P.y / CellSize));
}
struct sGrid
{
sGrid(int W, int H, double CellSize)
: m_W(W)
, m_H(H)
, m_CellSize(CellSize)
{
m_Grid.resize((m_H));
for (auto i = m_Grid.begin(); i != m_Grid.end(); i++){ i->resize(m_W); }
}
void Insert(const sPoint& P)
{
sGridPoint G = ImageToGrid(P, m_CellSize);
m_Grid[G.x][G.y] = P;
}
bool IsInNeighbourhood(sPoint Point, double MinDist, double CellSize)
{
sGridPoint G = ImageToGrid(Point, CellSize);
//number of adjacent cell to look for neighbour points
const int D = 5;
// Scan the neighbourhood of the Point in the grid
for (int i = G.x - D; i < G.x + D; i++)
{
for (int j = G.y - D; j < G.y + D; j++)
{
if (i >= 0 && i < m_W && j >= 0 && j < m_H)
{
sPoint P = m_Grid[i][j];
if (P.m_valid && GetDistance(P, Point) < MinDist){ return true; }
}
}
}
return false;
}
private:
int m_H;
int m_W;
double m_CellSize;
std::vector< std::vector< sPoint> > m_Grid;
};
template <typename PRNG>
sPoint PopRandom(std::vector<sPoint>& Points, PRNG& Generator)
{
const int Idx = Generator.RandomInt(Points.size() - 1);
const sPoint P = Points[Idx];
Points.erase(Points.begin() + Idx);
return P;
}
template <typename PRNG>
sPoint GenerateRandomPointAround(const sPoint& P, double MinDist, PRNG& Generator)
{
// Start with non-uniform distribution
double R1 = Generator.RandomDouble();
double R2 = Generator.RandomDouble();
// radius should be between MinDist and 2 * MinDist
double Radius = MinDist * (R1 + 1.0f);
//random angle
double Angle = 2 * 3.141592653589f * R2;
// the new point is generated around the point (x, y)
double X = P.x + Radius * cos(Angle);
double Y = P.y + Radius * sin(Angle);
return sPoint(X, Y);
}
// Return a vector of generated points
// NewPointsCount - refer to bridson-siggraph07-poissondisk.pdf
// for details (the value 'k')
// Circle - 'true' to fill a circle, 'false' to fill a rectangle
// MinDist - minimal distance estimator, use negative value for default
template <typename PRNG = DefaultPRNG>
std::vector<sPoint> GeneratePoissonPoints(rsize_t NumPoints, PRNG& Generator, int NewPointsCount = 30,
bool Circle = true, double MinDist = -1.0f)
{
if (MinDist < 0.0f)
{
MinDist = sqrt(double(NumPoints)) / double(NumPoints);
}
std::vector <sPoint> SamplePoints;
std::vector <sPoint> ProcessList;
// create the grid
double CellSize = MinDist / sqrt(2.0f);
int GridW = (int)(ceil)(1.0f / CellSize);
int GridH = (int)(ceil)(1.0f / CellSize);
sGrid Grid(GridW, GridH, CellSize);
sPoint FirstPoint;
do
{
FirstPoint = sPoint(Generator.RandomDouble(), Generator.RandomDouble());
} while (!(Circle ? FirstPoint.IsInCircle() : FirstPoint.IsInRectangle()));
//Update containers
ProcessList.push_back(FirstPoint);
SamplePoints.push_back(FirstPoint);
Grid.Insert(FirstPoint);
// generate new points for each point in the queue
while (!ProcessList.empty() && SamplePoints.size() < NumPoints)
{
#if POISSON_PROGRESS_INDICATOR
// a progress indicator, kind of
if (SamplePoints.size() % 100 == 0) std::cout << ".";
#endif // POISSON_PROGRESS_INDICATOR
sPoint Point = PopRandom<PRNG>(ProcessList, Generator);
for (int i = 0; i < NewPointsCount; i++)
{
sPoint NewPoint = GenerateRandomPointAround(Point, MinDist, Generator);
bool Fits = Circle ? NewPoint.IsInCircle() : NewPoint.IsInRectangle();
if (Fits && !Grid.IsInNeighbourhood(NewPoint, MinDist, CellSize))
{
ProcessList.push_back(NewPoint);
SamplePoints.push_back(NewPoint);
Grid.Insert(NewPoint);
continue;
}
}
}
#if POISSON_PROGRESS_INDICATOR
std::cout << std::endl << std::endl;
#endif // POISSON_PROGRESS_INDICATOR
return SamplePoints;
}
}
and the main program is:
poisson.cpp
#include "stdafx.h"
#include <vector>
#include <iostream>
#include <fstream>
#include <memory.h>
#define POISSON_PROGRESS_INDICATOR 1
#include "PoissonGenerator.h"
const int NumPoints = 20000; // minimal number of points to generate
int main()
{
PoissonGenerator::DefaultPRNG PRNG;
const auto Points =
PoissonGenerator::GeneratePoissonPoints(NumPoints,PRNG);
std::ofstream File("Poisson.txt", std::ios::out);
File << "NumPoints = " << Points.size() << std::endl;
for (const auto& p : Points)
{
File << " " << p.x << " " << p.y << std::endl;
}
system("PAUSE");
return 0;
}
Suppose you have a point in the space [0,1] x [0,1], in the form of a std::pair<double, double>, but desire points in the space [x,y] x [w,z].
The function object
struct ProjectTo {
double x, y, w, z;
std::pair<double, double> operator(std::pair<double, double> in)
{
return std::make_pair(in.first * (y - x) + x, in.second * (z - w) + w);
}
};
will transform such an input point into the desired output point.
Suppose further you have a std::vector<std::pair<double, double>> points, all drawn from the input distribution.
std::copy(points.begin(), points.end(), points.begin(), ProjectTo{ x, y, w, z });
Now you have a vector of points in the output space.

Non static members in C++

error C2648: 'stack::Y' : use of member as default parameter
requires static member
error C2648: 'stack::X' : use of member as default parameter
requires static member
IntelliSense: a nonstatic member reference must be relative to a
specific object
IntelliSense: a nonstatic member reference must be relative to a
specific object
Please, help to fix it
class stack{
node *head, *tail;
int maze[10][10], X, Y, _X, _Y;
public:
stack():head(0), tail(0){};
~stack();
void load();
void makelist(int = X, int = Y); //error is here
void push(int, int);
void pop();
void print();
};
void stack::load(){
ifstream fin("maze.txt");
fin >> X >> Y >> _X >> _Y;
cout << "Loaded matrix:" << endl << endl;
for (int i = 0; i < 10; i++){
for (int j = 0; j < 10; j++){
fin >> maze[i][j];
if (i == X && j == Y)
cout << "S ";
else if (i == _X && j == _Y)
cout << "F ";
else
cout << maze[i][j] << " ";
}
cout << endl;
}
}
void stack::makelist(int x, int y)
{
if (x == _X && y == _Y)
{
push(x, y);
print();
pop();
return;
}
if (x > 0) if (maze[x - 1][y] == 0) { maze[x][y] = 1; push(x, y); makelist(x - 1, y); pop(); maze[x][y] = 0; }
if (x < 9) if (maze[x + 1][y] == 0) { maze[x][y] = 1; push(x, y); makelist(x + 1, y); pop(); maze[x][y] = 0; }
if (y > 0) if (maze[x][y - 1] == 0) { maze[x][y] = 1; push(x, y); makelist(x, y - 1); pop(); maze[x][y] = 0; }
if (y < 9) if (maze[x][y + 1] == 0) { maze[x][y] = 1; push(x, y); makelist(x, y + 1); pop(); maze[x][y] = 0; }
}
<...>
int main()
{
stack obj;
obj.load();
obj.makelist();
system("pause");
return 0;
}
(this is a correction to my old answer, which was incorrect)
It seems that you want to use a non-static member as a default value for a parameter, and the compiler tells you this is impossible. You can use an overload as a workaround:
class stack{
node *head, *tail;
int maze[10][10], X, Y, _X, _Y;
public:
void makelist() {makelist(X, Y);} // I added this overload to do what you want
void makelist(int x, int x);
...
};
Some people would say overloading is better than using default values, because you probably don't want to support calling makelist with 1 parameter, only with 0 or 2 parameters (or, if you actually want this, you can add another overload, with 1 parameter).
You have a spurious "=" character in your code; replace your line with error with the following:
void makelist(int X, int Y);
The "=" character makes it look like the declaration has default parameters whose values are X and Y, which is totally not what you intended to do.
In addition, it is customary to have the same parameter names in declaration and definition:
void makelist(int x, int x); // declaration - I replaced X by x, Y by y
...
void stack::makelist(int x, int y) // definition - has lowercase names, which are good
{
...
}
Get rid of those = signs in the function declaration:
void makelist(int x, int y);
so it's just like the definition:
void stack::makelist(int x, int y)
{
Presuming you meant to use default values
void makelist(int x_ = X, int y_ = Y); //error is here
This is not allowed as the default values must be compiletime constants or compiletime addressable, which members of a not instantiated class are not.
The compiler needs an address be able to generate the code.
You can overload the function
void makelist(int x_, int y_);
void makelist() { makelist(X,Y); }
And so get nearly the same behaviour as you asked.
If you have a problem with _X & _Y then its because the compiler reserves _??? for itself or libraries.

std::map with Vector3 key VERSUS std::vector using a composite index

I'm creating a tilemap at the moment and trying to decide how to store and reference each tile. My 2 current options are between either :
A std::vector where I use a composite x,y,z calc as the key;
Or a std::map using a Vector3i as the key.
My question is : which method should I lean towards/prefer based on ease of use and/or performance. I guess memory/size/storage between the different methods could also come into the decision. Criticism is welcome as I'd like some opinions before basing my engine on this.
Here is an example using the composite vector :
#include <vector>
#include <algorithm>
#include <iostream>
unsigned int mapWidth = 10, mapHeight = 10, mapDepth = 2;
struct Vector3i {
Vector3i() {};
Vector3i(unsigned int x, unsigned int y, unsigned int z) : x(x), y(y), z(z) {}
unsigned int x, y, z;
};
struct Tile {
Tile() {};
std::vector<unsigned int> children;
bool visible;
Vector3i coord;
};
unsigned int getIndex(unsigned int x, unsigned int y, unsigned int z) {
return (y*mapWidth) + x + (z * (mapWidth * mapHeight));
}
int main() {
std::vector<Tile> tiles;
tiles.resize(mapWidth * mapHeight * mapDepth);
for( int x = 0; x < mapWidth; x++ ) {
for( int y = 0; y < mapHeight; y++ ) {
for( int z = 0; z < mapDepth; z++) {
unsigned int idx = getIndex(x,y,z);
tiles[idx].coord = Vector3i(x,y,z);
tiles[idx].visible = true;
tiles[idx].children.push_back(1);
}
}
}
std::for_each(tiles.begin(), tiles.end(), [&] (const Tile& tile) {
std::cout << tile.coord.x << "," << tile.coord.y << "," << tile.coord.z << std::endl;
});
const Tile& myTile = tiles[getIndex(1,1,1)];
std::cout << '\n' << myTile.coord.x << "," << myTile.coord.y << "," << myTile.coord.z << std::endl;
return 0;
};
And here is an example using the std::map method :
#include <vector>
#include <map>
#include <iostream>
#include <algorithm>
#include <functional>
struct Vector3i {
Vector3i() {};
Vector3i(unsigned int x, unsigned int y, unsigned int z) : x(x), y(y), z(z) {}
unsigned int x, y, z;
};
struct Tile {
std::vector<unsigned int> children;
bool visible;
Vector3i coord;
};
class comparator {
public:
bool operator()(const Vector3i& lhs, const Vector3i& rhs) const {
return lhs.x < rhs.x
|| ( lhs.x == rhs.x && ( lhs.y < rhs.y
|| ( lhs.y == rhs.y && lhs.z < rhs.z)));
}
};
int main() {
unsigned int mapWidth = 5, mapHeight = 5, mapDepth = 2;
std::map<Vector3i, Tile, comparator> tiles;
for( int x = 0; x < mapWidth; x++ ) {
for( int y = 0; y < mapHeight; y++ ) {
for( int z = 0; z < mapDepth; z++) {
Vector3i key(z,y,x);
Tile tile;
tile.coord = Vector3i(x,y,z);
tile.visible = true;
tile.children.push_back(1);
tiles.insert(std::make_pair<Vector3i, Tile>(key, tile));
}
}
}
for( std::map<Vector3i, Tile, comparator>::iterator iter = tiles.begin(); iter != tiles.end(); ++iter ) {
std::cout << iter->second.coord.x << "," << iter->second.coord.y << "," << iter->second.coord.z << std::endl;
}
auto found = tiles.find(Vector3i(1,1,1));
const Tile& myTile = found->second;
std::cout << '\n' << myTile.coord.x << "," << myTile.coord.y << "," << myTile.coord.z << std::endl;
return 0;
};
Ok, thanks a bunch!
Using a single vector to store your entire tilemap will require that the entire tilemap be in a contiguous block of memory. Depending on the size of the tilemap, that may or may not be a problem (with your current sizes, it won't be, but if it was ever expanded to a larger 3D space, it could easily get too large to try to allocate in a single contiguous block).
If you need to iterate through the 3D space in some orderly fashion, a map won't be your best container (since the items won't necessarily be in the logical order you want for display purposes).
Another potential solution is to use a vector of vector of vectors to tiles, which would allow for ease of iteration through your 3D space while also not requiring a massive contiguous block of data (only a 1D row of tiles would need to be contiguous).