c++: How to declare std::functions without creating member functions to assign to them - c++

I'm trying to write a "conditions" class to check if a given condition returns true or false, in an rpg game.
Conditions.h
#pragma once
#include <functional>
#include <vector>
#include <iostream>
class Conditions
{
public:
bool check(int i);
void initialize();
private:
std::vector<std::function<bool()>> functions;
};
Conditions.cpp
bool Conditions::check(int i)
{
if (i >= functions.size())
{
std::cout << "Conditions::functions's size is " << functions.size() << " but you've tried to enter: " << i << std::endl;
return false;
}
else
{
return functions[i]();
}
}
void Conditions::initialize()
{
//Here I want to initialize all the conditions manually and push them
//into functions member variable.
}
the question is , how can I create this functions without creating new member functions for each of them(there will be most likely more than 200 functions)
is it possible to write something like:
functions.push_back(
{
if(GameInfo::player.gold>200) return true;
else return false;
}
);

You are probably looking for lambdas:
functions.push_back([this]
{
if (GameInfo::player.gold > 200) return true;
else return false;
});
If you don't actually need to access any members of Conditions in the function, then you can also remove the this capture entirely:
functions.push_back([]
{
if (GameInfo::player.gold > 200) return true;
else return false;
});
By the way, your specific function example can be extremely simplified like this:
functions.push_back([]
{
return GameInfo::player.gold > 200;
});

Related

function parameters that are writeable only by the function itself - recursion counter

So I'm trying to write a recursive function that keeps track of how often it got called. Because of its recursive nature I won't be able to define an iterator inside of it (or maybe it's possible via a pointer?), since it would be redefined whenever the function gets called. So i figured I could use a param of the function itself:
int countRecursive(int cancelCondition, int counter = 0)
{
if(cancelCondition > 0)
{
return countRecursive(--cancelCondition, ++counter);
}
else
{
return counter;
}
}
Now the problem I'm facing is, that the counter would be writeable by the caller of the function, and I want to avoid that.
Then again, it wouldn't help to declare the counter as a const, right?
Is there a way to restrict the variable's manipulation to the function itself?
Or maybe my approach is deeply flawed in the first place?
The only way I can think of solving this, is to use a kind of "wrapper-function" that keeps track of how often the recursive function got called.
An example of what I want to avoid:
//inside main()
int foo {5};
int countToZero = countRecursive(foo, 10);
//countToZero would be 15 instead of 5
The user using my function should not be able to initially set the counter (in this case to 10).
You can take you function as is, and wrap it. One way I have in mind, which completely encapsulates the wrapping is by making your function a static member of a local class. To demonstrate:
int countRecursive(int cancelCondition)
{
struct hidden {
static int countRecursive(int cancelCondition, int counter = 0) {
if(cancelCondition > 0)
{
return countRecursive(--cancelCondition, ++counter);
}
else
{
return counter;
}
}
};
return hidden::countRecursive(cancelCondition);
}
Local classes are a nifty but rarely seen feature of C++. They possess some limitations, but fortunately can have static member functions. No code from outside can ever pass hidden::countRecursive an invalid counter. It's entirely under the control of the countRecursive.
If you can use something else than a free function, I would suggest to use some kind of functor to hold the count, but in case you cant, you may try to use something like this using friendship to do the trick:
#include <memory>
class Counter;
int countRecursive(int cancelCondition, std::unique_ptr<Counter> counter = nullptr);
class Counter {
int count = 0;
private:
friend int countRecursive(int, std::unique_ptr<Counter>);
Counter() = default; // the constructor can only be call within the function
// thus nobody can provide one
};
int countRecursive(int cancelCondition, std::unique_ptr<Counter> c)
{
if (c == nullptr)
c = std::unique_ptr<Counter>(new Counter());
if(cancelCondition > 0)
{
c->count++;
return countRecursive(--cancelCondition, std::move(c));
}
else
{
return c->count;
}
}
int main() {
return countRecursive(12);
}
You can encapsulate the counter:
struct counterRecParam {
counterRecParam(int c) : cancelCondition(c),counter(0) {}
private:
int cancelCondition;
int counter;
friend int countRecursive(counterRecParam);
};
Now the caller cannot modify the counter, and you only need to modify the function slightly:
int countRecursive(counterRecParam crp)
{
if(crp.cancelCondition > 0)
{
--crp.cancelCondition;
++crp.counter;
return countRecursive(crp);
}
else
{
return crp.counter;
}
}
And the implicit conversion lets you call it with an int
counterRecursive(5);
One way to do this is to use a functor. Here's a simple example:
#include <iostream>
class counter
{
public:
unsigned operator()(unsigned m, unsigned n)
{
// increment the count on every iteration
++count;
// rest of the function
if (m == 0)
{
return n + 1;
}
if (n == 0)
{
return operator()(m - 1, 1);
}
return operator()(m - 1, operator()(m, n - 1));
}
std::size_t get_count() const
{
return count;
}
private:
// call count
std::size_t count = 0;
};
int main()
{
auto f = counter();
auto res = f(4, 0);
std::cout << "Result: " << res << "\nNumber of calls: " << f.get_count() << std::endl;
return 0;
}
Output:
Result: 13
Number of calls: 107
Since the count is stored in the object itself, the user cannot overwrite it.
Have you tried using "static" counter variable. Static variables gets initialized just once, and are best candidates to be used as counter variables.

Return (\r) breaking cout

std::cout prints extra characters in my keyPressed string, probably because of "\r", for example, if keyPressed = "Right arrow", when I press the up arrow, it prints "keyPressed = Up arrowoww", then, when I press right arrow again, it prints "keyPressed = Right arrow" normally again, but if I press any arrow key except "Right arrow" it prints some unwanted extra characters at the end
Error example
Source code:
game.cpp
#include "engine.h"
#include <iomanip>
Engine eng;
int main() {
while (eng.isRunning) {
eng.getInput();
std::cout << std::setw(5);
std::cout << "\r X = " << eng.playerX;
std::cout << "| Y = " << eng.playerY;
std::cout << "| KEY = " << eng.keyPressed;
Sleep(100);
}
return 0;
}
engine.h
#ifndef ENGINE_H
#define ENGINE_H
#include <iostream>
#include <Windows.h>
#include <string>
class Engine {
public:
// Game
bool isRunning = true;
bool gettingInput = true;
// Player
int playerX = 1;
int playerY = 1;
char playerModel = 'P';
// Test / Debug
std::string keyPressed;
// Functions
char getInput() {
// Gets arrow keys states
while (this->gettingInput) {
this->keyPressed = "";
if (GetAsyncKeyState(VK_RIGHT)) {
// Right arrow key
this->playerX++;
this->keyPressed = "Right arrow";
break;
}
else if (GetAsyncKeyState(VK_LEFT)) {
// Left arrow key
this->playerX--;
this->keyPressed = "Left arrow";
break;
}
else if (GetAsyncKeyState(VK_UP)) {
// Up arrow key
this->playerY++;
this->keyPressed = "Up arrow";
break;
}
else if (GetAsyncKeyState(VK_DOWN)) {
// Down arrow key
this->playerY--;
this->keyPressed = "Down arrow";
break;
}
else if (GetAsyncKeyState(VK_END)) {
exit(0);
}
Sleep(255);
}
}
};
#endif
Best / easiest way to fix this?
I searched and tested for 3 days but didn't find anything, please, help me.
Since you're overwriting the previous output, when you print a shorter string the extra characters from the previous output are still displayed. Replace the \r with a \n to see what's actually being output.
You can output some spaces after your key name to overwrite those extra characters with spaces and erase them.
After looking over your provided code I do see a few issues or concerns with the code design: I'll break it down and explain some of the things that I see that could improve the quality of your code. I will start with your main.cpp then move on to your Engine class.
You initially have this:
#include "engine.h"
#include <iomanip>
Engine eng;
int main() {
while (eng.isRunning) {
eng.getInput();
std::cout << std::setw(5);
std::cout << "\r X = " << eng.playerX;
std::cout << "| Y = " << eng.playerY;
std::cout << "| KEY = " << eng.keyPressed;
Sleep(100);
}
return 0;
}
The first main issue that I see is that you have declared Engine eng at the global level. We can fix this by
#include "engine.h"
#include <iostream>
#include <iomanip>
int main() {
Engine eng; // declare it here as the first object in main; now it has local
// scope within main's function and is now in Automatic Storage
// instead of Global Storage.
while( ... ) {
// ....
}
return 0;
};
The next issue starts with while loop's conditional expression in the main function.
You currently have:
while( engine.isRunning ) { //... }
This is okay but this is more of an issue with your Engine class's design. Here you are providing a public member that anyone can access. So let's look at your class declaration/definition; you currently have:
#ifndef ENGINE_H
#define ENGINE_H
#include <iostream>
#include <Windows.h>
#include <string>
class Engine {
public:
// Game
bool isRunning = true;
bool gettingInput = true;
// Player
int playerX = 1;
int playerY = 1;
char playerModel = 'P';
// Test / Debug
std::string keyPressed;
// Functions
char getInput() { // ... }
};
#endif
Here you should protect your data members and have access modifiers functions to them:
#ifndef ENGINE_H
#define ENGINE_H
#include <iostream>
#include <Windows.h>
#include <string>
class Engine {
private:
bool isRunning;
bool gettingInput;
// Player
int playerX;
int playerY;
char playerModel;
// Test / Debug
std::string keyPressed;
public:
Engine() :
isRunning( false ),
isGettingInput( false ),
playerX( 1 ),
playerY( 1 ),
playerModel( 'P' )
{}
void run() { isRunning = true; // set or call other things here... }
// Since we protected our members variables by making them private,
// we now need some access functions to retrieve and modify them.
bool isActive() const { return isRunning; } // make this const so it doesn't change anything
void toggleIsActive() { isRunning = !isRunning; }
bool retrievingInput() const { return isGettingInput; }
void toggleRetrievingInput() { isGettingInput = !isGettingInput; }
int getPlayerX() const { return playerX; }
void setPlayerX( int newX ) { playerX = newX; }
int getPlayerY() const { return playerY; }
void setPlayerY( int newY ) { playerY = newY; }
// set both in one function call
void setPlayerPosition( int newX, int newY ) {
playerX = newX;
playerY = newY;
}
char getPlayerModel() const { return playerModel; }
// don't know if you want to change this: uncomment if you do
// void setPlayerModel( char c ) { playerModel = c; }
std::string& getPressedKey() const { return keyPressed; }
char getInput() { // ... }
};
This should fix the interface design of your class. The only major difference here is that I had set your Boolean member variables to false by default because typically when you first start an Engine it is currently not already running. So to fix this we can call a public run function that will trigger this. So main would look like this instead:
int main () {
Engine eng;
eng.run(); // this now starts the engine sets the flag to true
while (...) { //... }
return 0;
}
However, I have also seen few concerns in your Engine's getInput() function, so let's take a look at it.
char getInput() {
// Gets arrow keys states
while (this->gettingInput) {
this->keyPressed = "";
if (GetAsyncKeyState(VK_RIGHT)) {
// Right arrow key
this->playerX++;
this->keyPressed = "Right arrow";
break;
}
else if (GetAsyncKeyState(VK_LEFT)) {
// Left arrow key
this->playerX--;
this->keyPressed = "Left arrow";
break;
}
else if (GetAsyncKeyState(VK_UP)) {
// Up arrow key
this->playerY++;
this->keyPressed = "Up arrow";
break;
}
else if (GetAsyncKeyState(VK_DOWN)) {
// Down arrow key
this->playerY--;
this->keyPressed = "Down arrow";
break;
}
else if (GetAsyncKeyState(VK_END)) {
exit(0);
}
Sleep(255);
}
}
The first part is the while loop's condition statement and your class's member. Originally you have this set to true by default, yet no where in the code did I see this value being updated. We don't need to change this but the fix is simple now that we have a way to change this member through a public interface call. Since I have made your isGettingInput false by default; you can now set this within this function before you enter the while loop. The only last issue that I see is that when this function is called back in main's while loop; this function never return's a value and the return value is never being used.
As to your actual problem with your bug for cout user : 1201programalarm has pretty much already answered that for you. Just thought I'd help you out a little bit more with your code.

How to check if bool method returns value in an if statement C++

I'm having a go at creating classes and have created this method inside
Input.cpp:
bool Input::CheckKeyPress(char key)
{
SDL_Event ev;
while (SDL_PollEvent(&ev))
{
keyState = SDL_GetKeyboardState(NULL);
if (ev.type == SDL_KEYDOWN)
{
switch (key)
{
case 'w' :
if (keyState[SDL_SCANCODE_W])
{
return 1;
}
else
{
return 0;
}
case 'a' :
if (keyState[SDL_SCANCODE_A])
{
return 1;
}
else
{
return 0;
}
case 's' :
if (keyState[SDL_SCANCODE_S])
{
return 1;
}
else
{
return 0;
}
case 'd' :
if (keyState[SDL_SCANCODE_D])
{
return 1;
}
else
{
return 0;
}
}
}
}
}
I try to use it in an if-statement in my main class like so:
if (bool Input::CheckKeyPress(w))
{
//do stuff
}
However as expected I get an error saying: "A function type is not allowed here" So what do I do?
Just write:
if (CheckKeyPress(w))
{
//do stuff
}
You have already told the compiler that the CheckKeyPress() method returns a bool. Here, you are just calling the function, so you don't need to mention the return type again. When the control will call the function CheckKeyPress(), it will return a bool value that would be checked for its truth within the if statement.
Note: There are two possibilities:
Instance is a different class:
If Instance is altogether a different class and CheckKeyPress() is
one of the methods that it contains, then you first need to create an object of the Instance class like below:
Instance it = new Instance(); //or just Instance it;
and then access the function via:
it.CheckKeyPress();
If the method is static:
In this case you need to call the method as:
Input::CheckKeyPress(w)
without just the return type (bool).
Hope this is helpful. Thank you for your inputs, #user4581301.

Error assigning object to pointer c++

Me and my friend are making a text based game in c++ for fun, and to learn a little more. I have been trying to use pointers to classes, but am having no luck, and some errors are occurring which make absolutely no sense to me at all, and am hoping someone can help me.
Code:
//Map.h
#include "Player.h"
class Map
{
//Virtual functions
};
class StartMap : public Map
{
//Code
}Start;
class JungleMap : public Map
{
//Code
}Jungle;
class RiverMap : public Map
{
//Code
}River;
//Player.h
#ifndef MAP_H
#define MAP_H
#endif
class Player
{
private:
Map *PlayerMap;
//Other variables
public:
void Initialize()
{
//Initialize variables
PlayerMap = &Start; //This is where the error occurs, says there's a
//<error-type>*Player::PlayerMap. Tried putting
//this->PlayerMap = &Start, didn't help
//There's no error when I make the pointer
}
//Bunch of other functions
}Player;
Okay, here's my code since I decided to add .cpp files:
//Command.h
class Command
{
private:
string GameCommand;
void Trim();
public:
Command (string command) {GameCommand = command;}
Command () {}
void operator = (string command) {GameCommand = command;}
void ReadCommand();
string Print();
}
//Command.cpp
#include <iostream>
#include <string>
#include "Command.h"
#include "Parameter.h"
using namespace std;
void Command::Trim()
{
int LeadingPos = 0, MidCount = 0, TrailingPos = GameCommand.length()-1, Size = 0;
string TempCommand = "";
while (GameCommand[LeadingPos] == ' '){LeadingPos += 1;}
while (GameCommand[TrailingPos] == ' '){TrailingPos -= 1;}
Size = ((TrailingPos+1)-LeadingPos);
for (int loops = 0; loops < Size; loops++)
{
if (MidCount > 0 && GameCommand[LeadingPos] == ' ')
{
LeadingPos += 1;
}
else
{
if (GameCommand[LeadingPos] == ' ')
{
MidCount += 1;
}
TempCommand += GameCommand[LeadingPos];
LeadingPos += 1;
}
}
GameCommand = TempCommand;
}
void Command::ReadCommand()
{
Trim();
string Parameter;
if (GameCommand.substr(0,3) == "go ")
{
Parameter = GameCommand.substr(3,string::npos);
CommandParameter.Go(Parameter);
}
else if (GameCommand.substr(0,4) == "dig ")
{
Parameter = GameCommand.substr(4,string::npos);
CommandParameter.Dig(Parameter);
}
else if (GameCommand.substr(0,4) == "eat ")
{
Parameter = GameCommand.substr(4,string::npos);
CommandParameter.Eat(Parameter);
}
else if (GameCommand.substr(0,4) == "exit" || GameCommand.substr(0,4) == "quit")
{
exit(0);
}
else if (GameCommand.substr(0,4) == "use ")
{
Parameter = GameCommand.substr(4,string::npos);
CommandParameter.Use(Parameter);
}
else if (GameCommand.substr(0,5) == "drop ")
{
Parameter = GameCommand.substr(5,string::npos);
CommandParameter.Drop(Parameter);
}
else if (GameCommand.substr(0,5) == "grab " || GameCommand.substr(0,5) == "take ")
{
Parameter = GameCommand.substr(5,string::npos);
CommandParameter.Pickup(Parameter);
}
else if (GameCommand.substr(0,5) == "help ")
{
Parameter = GameCommand.substr(5,string::npos);
CommandParameter.Help(Parameter);
}
else if (GameCommand.substr(0,5) == "look ")
{
Parameter = GameCommand.substr(5,string::npos);
CommandParameter.Look(Parameter);
}
else if (GameCommand.substr(0,5) == "sleep")
{
CommandParameter.Sleep();
}
else if (GameCommand.substr(0,6) == "check ")
{
Parameter = GameCommand.substr(6,string::npos);
CommandParameter.Check(Parameter);
}
else if (GameCommand.substr(0,6) == "climb ")
{
Parameter = GameCommand.substr(6,string::npos);
CommandParameter.Climb(Parameter);
}
else if (GameCommand.substr(0,6) == "throw ")
{
Parameter = GameCommand.substr(6,string::npos);
CommandParameter.Throw(Parameter);
}
else if (GameCommand.substr(0,7) == "attack ")
{
Parameter = GameCommand.substr(7,string::npos);
CommandParameter.Attack(Parameter);
}
else if (GameCommand.substr(0,7) == "search ")
{
Parameter = GameCommand.substr(7,string::npos);
CommandParameter.Search(Parameter);
}
else
{
cout << "Not a valid command.\n";
}
}
string Print()
{
return GameCommand;
}
The string GameCommand is what's not working.
class StartMap : public Map;
is syntactically incorrect. You need
class StartMap : public Map
{
// Details of class
} Start;
You need to make similar changes to JungleMap and RiverMap.
First thing I noticed was the semi-colon after each inheritance declaration..
class XXXXX : public Map; <-- that semi-colon shouldn't be there..
In the initialize function, I'm fairly certain you mean PlayerMap = new StartMap();
You'll need a destructor to delete it and a copy, move constructor as well as an assignment operator in order to assign, move or copy the class.
You can follow this to make the class conform to RAII: What is the copy-and-swap idiom?
There are lots of problems with your code layout.
This doesn't do anything:
//Player.h
#ifndef MAP_H
#define MAP_H
#endif
I guess you are trying to do an include guard. The proper layout is:
#ifndef PLAYER_H
#define PLAYER_H
// all your code for the header file goes here
class Player
{
// ....
};
#endif // no more code after this line
The next issue is that Player.h should include Map.h, not the other way around. Imagine you are the compiler. You are processing Player.h. You get down as far as Map *PlayerMap; . But you don't know what Map is because you haven't seen Map.h yet. So you have to give an error and stop compiling.
The map definitions in Map.h should look like:
class StartMap : public Map
{
//Code
};
The Start; you had on the end is poor style. It would cause undefined behaviour if two different .cpp files included Map.h because there would be two different global variables with the same name.
Moving onto the void Map::Initialize() function. You're supposed to use the constructor for initialization. Either way, my suggestion is that you don't implement this in Player.h. Instead, just have void Initialize();, and then in Map.cpp you could have:
// the global variables
StartMap start_map;
JungleMap jungle_map;
void Map::Initialize()
{
player_map = &start_map;
}
It's a good idea to use a different naming convention for classes than for variables. So that when someone sees StartMap for example, they know immediately whether it is a class name or a variable name.

Hiding iteration in a function

Only got rough idea of what I want, perhaps someone could pad it out and/or tell me if its possible.
I would like to simplify my multiply nested loops, to that end I would like to be able to call a function (for example that uses boost::filesystem) that returns a file in a directory, each successive call would return the next file, until all were exhausted. Also i would like to be able to do this with a vector, and have the function return successive elements.
Any ideas how this could be done? thanks
Create a functor: an object that is called like a function.
The object will hold the query results and the current state of the query. You define an operator() so the object can be called as if it were a function. Each time this function is called you return one result and update the object's internal state.
Example:
#include <iostream>
using namespace std;
class CountDown {
unsigned count;
public:
CountDown(unsigned count) : count(count) {}
bool operator()() { return count-- > 0; }
};
int main()
{
CountDown cd(5);
while( cd() ) {
cout << "Counting" << endl;
}
return 0;
}
use Iterator pattern. In Java you'd have smth like this:
class FileIterator {
private int index;
private File[] files;
public FileIterator(File[] files) {
this.files = files;
this.index = 0;
}
public boolean hasNext() {
if (index < files.length - 1) {
return true;
} else {
return false;
}
}
public File next() {
return this.files [index ++];
}
}
and you'd use it like this:
FileIterator it = new FileIterator(theFiles);
while (it.hasNext()) {
File f = it.next();
}
You can use BOOST_FOREACH to simplify loops link to docs and stackoverflow