Use a member of struct vector in nested classes - c++

I have written some codes like this
struct connectedGrids
{
int Coord[3];
enum faceOrien_Type
{
xNeg = 0,
xPos = 1,
yNeg = 2,
yPos = 3,
zNeg = 4,
zPos = 5
}faceOrien;
};
class face
{
public:
vector<connectedGrids> ConnectedGrids;
};
class grid
{
public:
face Face;
}
I have initialized an object Grid in the main.cpp
vector<vector<vector<grid> > > Grid = initGrid();
And I want to call the member of struct vector in nested classes like this:
Grid[i][j][k].Face.ConnectedGrids.faceOrien = 1;
But it gave me an error saying
faceOrien is not the member of std::vector<_Ty>
I'm new to C++, and I can't get out where is wrong :(

Well, ConnectedGrids is a vector, you declared it as
vector<connectedGrids> ConnectedGrids;
So, which of the connectedGrids structures inside that vector did you want to modify?

Grid[i][j][k].Face.ConnectedGrids is a vector. It surely doesn't have faceOrien member. You should add something to the vector and then access its elements, for example:
Grid[i][j][k].Face.ConnectedGrids.push_back(connectedGrids());
Grid[i][j][k].Face.ConnectedGrids[someIndex].faceOrien = 1;

ConnectedGruds is an vector<connectedGrids>, but you are treating it like a connectedGrids object.
Grid[i][j][k].Face.ConnectedGrids[0].faceOrien = 1;
// ^^^ assumes size > 0

Related

Access child in nested vector of unknown depth using vector of indexes

My goal is to be able to have a vector of indexes and navigate to that in a class with a vector of variants of vectors and that class.
Say I have an "index vector" of unknown size with {0, 4, 7, 2} I would want to somehow use that to access someVector[0][4][7][2].
someVector is of a class node
defined as:
class node
{
public:
node operator[](unsigned int index)
{
return std::get<node>(children[index]);
}
private:
std::vector<std::variant<node, std::string>> children;
}
I had the idea of using a loop and a reference but couldn't figure that out.
My idea was something along the lines of
node elementRef = &nodeObject;
for (int i = 0; i < vector.size(); i++)
{
tempElementRef = &elementRef[indexVector[I]];
elementRef = tempElementRef;
}
With C++20 you can do it like this:
node accessNode(node n, std::span<unsigned int> span)
{
return span.size() ? accessNode(n[span[0]], span.subspan(1)) : n;
}
example usage:
std::vector<unsigned int> coordinates = {0, 4, 7, 2};
accessNode(someNode, coordinates);
note: Handling exceptions from bad indices or children that are not nodes is left up to you.

c++, boost, store objects in multidimensional array without default constructor

I want to store thousands of interpolation functions in a multidimensional array, preferable the one from boost. The main problem is that the interpolation function I use is a class that does not have a default constructor. This prohibits me to initialize the multidimensional array.
What I wish I could do:
double func(const double& x1, const double& x2, const double& x3)
{
return x1 + x2 + x3;
};
int main()
{
std::vector<double> x1 {0, 1, 2, 3};
std::vector<double> x2 {1.1, 1.2, 1.3, 1.4, 1.5};
std::vector<double> x3 {0, 10, 20, 30, 40};
std::vector<double> y(20, std::vector<double>(5));
boost::multi_array<Linear_interp, 2> Storage(boost::extents[4][5]);
typedef std::vector<double>::size_type vd_sz;
int n = 0;
for (vd_sz i_x1 = 0; i_x1 < x1.size(); ++i_x1) {
for (vd_sz i_x2 = 0; i_x2 < x2.size(); ++i_x2) {
for( vd_sz i_x3 = 0; i_x3 < x3.size(); ++i_x3) {
y[n][i_x3] = func(x1[i_x1], x2[i_x2], x3[i_x3]);
}
Linear_interp myInterp(x3, y);
Storage[i_x1][i_x2] = myInterp;
++n;
}
}
// Sample usage
double z = Storage[3][2].interp(23);
return 0;
}
The problem is that the class Linear_interp has no default constructor (the class is similar to this class 1), therefore boost::multi_array can not initialize the array.
Note that I initialize all interpolations inside a loop and therefore, I need to store these objects. A simple pointer to the object will not work, since the object will be overwritten in each loop.
In reality, I will have much more dimensions (atm I have 10), and multi_array is a nice container to handle these. Additionally, Interpolations in later loops, will take interpolations from previous loops (i.e. I have a recursive problem).
EDIT 1: Minor code correction.
EDIT 2: code correction: in the previous version, i did not save the "y"s which lead to unwanted results.
Well pointer WILL work. If you will declare your array as:
multi_array<Linear_interp*, 2>
to store pointers to the the objects instead of objects themselves.
Then in the loop you could allocate new object each time it would be necessary and put it to the appropriate place in the array. Just use new keyword to create new Linear_interp object inside the loop. Here is code to use inside the loop:
Storage[i_x1][i_x2] = new Linear_interp(x3, y);
I'm not a boost expert, but I'm sure there is an equivalent solution. You could do the following steps:
Make sure to build a complete "matrix" with empty innermost arrays. Something like the following (using std::vector) works for 3 dimensions:
std::vector<std::vector<std::vector<Linear_interp>>> Storage;
Storage.resize(x1.size());
for (vd_sz i_x1 = 0; i_x1 < x1.size(); i_x1++) {
Storage[i_x1].resize(x2.size());
}
At this point, Storage[i][j] is an existing, but empty std::vector<Linear_interp>. So now you can use std::vector::emplace_back or (::push_back with C++11) to fill your Storage. Going back to two dimensions and your original code, something like this will do the job:
typedef std::vector<double>::size_type vd_sz;
for (vd_sz i_x1 = 0; i_x1 < x1.size(); i_x1++) {
for (vd_sz i_x2 = 0; i_x2 < x2.size(); i_x2++) {
for( vd_sz i_x3 = 0; i_x3 < x3.size(); i_x3++) {
y[i_x3] = func(x1[i_x1], x2[i_x2], x3[i_x3]);
}
Storage[i_x1][i_x2].emplace_back(x3, y);
// or: Storage[i_x1][i_x2].push_back(Linear_interp(x3, y));
}
}
Using push_back or similar methods, will only call a copy c'tor and hence work for your non-default-constructible type Linear_interp.

Passing an enum of a structure to other functions and assigning the values

I'm writing a Snake game in C++, I have a structure for a section of the snake which contains, data such as x position, y position, direction etc.
I have it all working, setting all the data to integers, I just would like to change some of the data types to enum's because it looks a lot neater and easier to understand.
I've tried lots and looked online but I can't seem to find anything.
This is some of the Structure:
struct SnakeSection
{
int snakePosX;
int snakePosY;
int SectionType;
// Tail = 0, Body = 1, Head = 2
int animation;
enum Direction
{
Up = 0,
Right = 1,
Down = 2,
Left = 3
};
};
My attempt at trying to pass one of the Directions to another function:
void PlayerSnake::createSnake()
{
// Parameters are direction, x and y pos, the blocks are 32x32
addSection(SnakeSection::Direction::Right, mStartX, mStartY, 2);
}
Then I tried setting the direction to the one passed in in that function:
void PlayerSnake::addSection(SnakeSection::Direction dir, int x, int y, int type)
{
//Create a temp variable of a Snake part structure
SnakeSection bufferSnake;
bufferSnake.Direction = dir;
bufferSnake.animation = 0;
//is it head tail or what? This is stored in the Snake section struct
//TODO Add different sprites for each section
bufferSnake.SectionType = type;
//assign the x and y position parameters to the snake section struct buffer
bufferSnake.snakePosX = x;
bufferSnake.snakePosY = y;
//Push the new section to the back of the snake.
lSnake.push_back(bufferSnake);
}
error: invalid use of enum SnakeSection::Direction
Thanks
The error on the following line ...
bufferSnake.Direction = dir;
... is reasoned, that besides declaring the enum type, you'll still have to have a class member variable to store it:
struct SnakeSection
{
int snakePosX;
int snakePosY;
int SectionType;
// Tail = 0, Body = 1, Head = 2
int animation;
enum Direction
{
Up = 0,
Right = 1,
Down = 2,
Left = 3
};
Direction direction_; // <<<<<<<<<<<<<< THAT'S WHAT'S MISSING IN YOUR CODE
};
And refer to
bufferSnake.direction_= dir; // <<<<<<<<<<<<<< THAT'S THE MEMBER VARIABLE YOU'LL
// HAVE TO REFER TO!

OpenGL - drawing objects using text file

I have loaded an array from a text file, which contains positions of objects, and it looks like this:
0,0,0,5
0,5,0,0
0,0,5,0
0,5,5,0
The object looks like this:
struct object
{
int x, y, value;
}
Where x,y are coordinates, and value is 1 or 0 (it tells if an object was "picked", all objects have 1 at the beginning). Objects are stored in an array object obj_array[5].
To draw them, I use this function:
(BOARD_Y and BOARD_Y is size of the array, here is 4x4)
void draw_board(){
for (int iy = 0; iy < BOARD_Y; iy++) {
for (int ix = 0; ix < BOARD_X; ix++) {
if ( (board[iy][ix] == 5) )
{
glPushMatrix();
glTranslatef( ix, iy, 0 );
glutSolidCube(1);
glPopMatrix();
}
}
}
}
And it draws all of them perfectly. But I want to skip drawing an object, if its value is 0 (the object was picked by a player). How can I do this?
Okey, I can see what's going on; you've complicated the things a bit. There's no way to access the arbitrary object just from this loop, apart from pretty stupid comparison of position:
if ( (board[iy][ix] == 5) ) {
for (auto const& obj : objects) {
if (obj.x == ix && obj.y == iy) {
// obj is the object in given position
// ...
break;
}
}
}
Don't do that.
Instead either store some reference to the objects on the board. By reference I mean (not limited to!):
An unique object ID
Pointer to the object
Then, you will be able to access the object residing on given tile much faster and easier. If you want examples, drop a comment, but I think both options are fairly easy to implement.
If you still want to hold these "5" inside, change board to array of structs. And oh, please use std::array instead of int**.
Here's the example
using id_t = unsigned;
std::map<id_t, object> objects;
constexpr std::size_t size_x = 4, size_y = 4;
std::array<id_t, size_x * size_y> board;
Let's assume that id equal to 0 means that the object is not there.
Now you can access the specific object by:
unsigned x, y;
id_t obj_id = board[x + size_x * y];
if (obj_id != 0) // is there any object?
if (objects[obj_id].value != 0) // is its value equal to 0?
// ...
And set it by board[...] = obj;
Easy way to generate unique id for every object is just to increment the counter.
id_t last_id = 1;
objects[last_id++] = obj_id;

Mapping an integer to an array

I recently started with C++; I'm an hobby programmer, and I know a bit of Python.
I programmed a little snake. I wanted to insert another snake guided by the computer.
I decided to put the possible direction that the snake can take in an enum:
enum directions{UP, DOWN, RIGHT, LEFT, IN, OUT, FW, RW,NONE};
void fill_map(std::map<directions,V4> &map_vec);
void fill_map(std::map<int, directions*> &map_dir);
void fill_map(std::map<directions,directions> &map);
and map the enum for the needed function:
void fill_map(std::map<directions,V4> &map_vec){
map_vec[UP] = V4(0,1,0,0);
map_vec[DOWN] = V4(0,-1,0,0);
//others
}
void fill_map(std::map<directions, directions> &map){
map[UP]= DOWN;
map[DOWN]= UP;
//others
}
void fill_map_axis(std::map<int, directions*> &map_dir){
directions array_x[2] = {RIGHT,LEFT};
map_dir[0] = array_x;
directions array_y[2] = {UP,DOWN};//store the array
map_dir[1] = array_y;
directions array_z[2] = {FW,RW};//store the array
map_dir[2] = array_z;
directions array_w[2] = {IN,OUT};//store the array
map_dir[3] = array_w;
}
The fill_map functions are called in the snake constructor.
Basically what I wanted to do in the fill_map_axis is to map an integer corresponding to the index of the coordinate (0 coord x, 1 coord y etc) and map the two directions that move along those axis.
So I stored an array of two directions.
Now I call the function:
directions SnakeCPU::find_dir(V4 point){
//point is the target point
directions dir;
int index = get_coord_index(point); //get the index where to move
double diff = head_pos[index]-point[index]; //find the difference between the head and the target point
directions* axis = dir_coords[index]; //call the map containing the directions stored in an array.
if(diff<0.){
dir = *axis; //use the first
}
else if(diff>0.) {
axis++;
dir = *axis; //use the second
}
else{
dir = NONE;
}
return dir;
}
Although the map are initialized in the Snake constructor, it seems that the returned value from the pointer axis is a random memory block.
So my question: do you see a mistake in the code? did I used the pointer axis with sense?
I'm really not expert with pointer; in Python the map is instantiated with a dictionary like this:
dir_coords = {0:[LEFT,RIGHT], ...}
so I just need to call it:
axis = dir_coords[index]
dir = axis[0]
#or
dir = axis[1]
edit:
Snake constructor:
Snake::Snake()
{
fill_map(dir_vectors);
fill_map(dir_coords);
fill_map(opposite_dir);
head_pos = V4(0.,0.,0.,0.);
//other stuff...
}
Just a shot in the blue, here is how I would design this.
#include <map>
enum EDirection { NONE = 0, UP, DOWN, RIGHT, LEFT, IN, OUT, FW, RW };
typedef std::map<EDirection, V4> DirectionMap;
typedef std::pair<EDirection, EDirection> DirectionPair;
typedef std::map<int, DirectionPair> PairMap;
extern const DirectionMap map_vec {
{ UP, (0, 1, 0, 0) },
{ DOWN, (0,-1, 0, 0) },
// ...
}; // using C++11 initialization lists for convenience
extern const PairMap map_dir {
{ 0, { RIGHT, LEFT } },
{ 1, { UP, DOWN } },
// ...
};
Here I decided to make map_vec and map_dir global constants, because I gathered that that's essentially what they are. To initialize those, I rely on the new C++11 initialization syntax. If that's not an option, we can also fill the map in the traditional way:
PairMap map_dir;
map_dir.insert(std::make_pair(0, DirectionPair(RIGHT, LEFT)));
map_dir.insert(std::make_pair(1, DirectionPair(UP, DOWN)));
// ...
DirectionMap map_vec;
map_vec.insert(std::make_pair(UP, V4(0, 1, 0, 0)));
map_vec.insert(std::make_pair(DOWN, V4(0,-1, 0, 0)));
// ...
(Yes, you can also write map_dir[0] = DirectionPair(RIGHT, LEFT)'. I don't like the square brackets, though, they feel too violent for my taste.)
As Kerrek said, you filled map_dir with automatic scoped variables, which means they are automatically destroyed when the function ended.
void fill_map_axis(std::map<int, directions*> &map_dir){
//This variable will be destroyed when the function ends
directions array_x[2] = {RIGHT,LEFT};
map_dir[0] = array_x; //should have a warning at least, probably not compile
What you probably want is actual directions in the map
void fill_map_axis(std::map<int, std::pair<directions, directions> > &map_dir){
//This variable will be destroyed when the function ends
std::pair<directions, directions> array_x = {RIGHT,LEFT};
map_dir[0] = array_x; //makes a copy