Am I using function pointers correctly? - c++

I have a function that looks something like this in pseudocode:
std::string option = "option1" // one of n options, user supplied
for (int i = 0; i < 100000; i++) {
if (option == "option1") {
doFunction1a();
} else if (option == "option2") {
doFunction2a();
} else if (option == "option3") {
doFunction3a();
}
// more code...
if (option == "option1") {
doFunction1b();
} else if (option == "option2") {
doFunction2b();
} else if (option == "option3") {
doFunction3b();
}
}
However, I could avoid the repeated if statement inside the loop by doing something like this:
std::string option = "option1" // one of n options, user supplied
int (*doFunctiona)(int, int);
int (*doFunctionb)(int, int);
if (option == "option1") {
doFunctiona = doFunction1a;
doFunctionb = doFunction1b;
} else if (option == "option2") {
doFunctiona = doFunction2a;
doFunctionb = doFunction2b;
} else if (option == "option3") {
doFunctiona = doFunction3a;
doFunctionb = doFunction3b;
}
for (int i = 0; i < 100000; i++) {
doFunctiona();
// more code...
doFunctionb();
}
I realize that this will have little effect on performance (the time spend by the functions dominates the time it takes to execute the if statement).
However, In terms of "good coding practices", is this a good way to set up variable function calling? With "good" I mean: (1) easily expandable, there could easily be 20 options in the future; 2) results in readable code. I'm hoping there exists some kind of standard method for accomplishing this. If not, feel free to close as opinion based.

Just use an unordered_map and spare yourself the if-else-if-orgy:
std::unordered_map<std::string, std::vector<int (*)(int, int)>> functions;
functions.insert({ "option1", { doFunction1a, doFunction1b } });
...
const auto& vec = functions["option1"];
for(auto& f : vec) f(1, 2);

Beside using map I recommend to use std::function and lambdas which will give you more flexibility and syntax is more friendly (at least for me):
std::unordered_map<std::string, std::function<void()>> functions {
{
"option1",
[] {
functionA();
functionB();
}
},
{
"option2",
[] {
functionC();
functionD();
}
}
};
auto optionFuncIt = functions.find("option1");
if (optionFuncIt != functions.end()) {
optionFuncIt->second();
} else {
std::cerr << "Invalid option name" << std::endl;
}

Related

c++ macro using variable from an other macro

I need to make foo compile by implementing the macros for it:
int foo(std::string tag)
{
SWITCH_STRING(tag)
{
STRING_CASE(a)
{
return 1;
}
STRING_CASE(b)
{
return 2;
}
STRING_CASE(abc)
{
return 3;
}
STRING_ELSE
{
return -1;
}
}
}
I would like to use the tag parameter in SWITCH_STRING(tag) and compare it to the letter parameter in STRING_CASE(letter), to implement this switch like syntax, I'm stuck for a while and new to macros in c++ could you offer a solution to how to implement the macros please?
#include <iostream>
#include <string>
// Write macros here |
#define SWITCH_STRING(tag)
#define STRING_CASE(letter) letter == tag ? true : false
#define STRING_ELSE
I have to admit: Macros can be fun. We all should know that they should be avoided. Though, as this is an exercise about macros, we can put the discussion whether to use a macro or not aside.
The point of the exercise is that you cannot (directly) switch on a std::string. This answer shows how this limitation can be worked-around. Being required to write exremely verbose repetetive code, the macro is kind of justified. For the sake of completeness I want to add how it can be solved using your original approach, using a series of if instead of the switch.
First, I write the function that does what is asked for without any macro involved:
int foo(std::string tag)
{
std::string& temp = tag;
{
if (temp == "a")
{
return 1;
}
if (temp == "b")
{
return 2;
}
if (temp == "abc")
{
return 3;
}
{
return -1;
}
}
}
It isnt that nice that it uses ifs not else if that should be prefered for mutually exclusive cases. However, as each case returns, the result wont differ (if that isnt the case, you'll have to add some goto vodoo as outlined in the other answer). Having that, it is straightforward to see what macros are needed:
#define SWITCH_STRING(tag) std::string& temp = tag;
#define STRING_CASE(X) if (temp == #X)
#define STRING_ELSE
This kind of answers your question about how to use the parameter of one macro in a second one: You don't. Instead you can use a reference whose name does not depend on the actual name of tag anymore.
Full example
What you might do to switch on string:
constexpr std::size_t myhash(std::string_view) { /* .. */ }
int foo(const std::string& tag)
{
switch (tag)
{
case myhash("a"): { return 1; }
case myhash("b"): { return 2; }
case myhash("abc"): { return 3; }
default: { return -1; }
}
}
That doesn't need MACRO.
If you have collisions with your cases, compilation would fail (same value in switch)
and you will need another hash function.
If you want to prevent collisions (from input string), you might do:
constexpr std::size_t myhash(std::string_view) { /* .. */ }
int foo(const std::string& tag)
{
switch (tag)
{
case myhash("a"): { if (tag != "a") { goto def; } return 1; }
case myhash("b"): { if (tag != "b") { goto def; } return 2; }
case myhash("abc"): { if (tag != "abc") { goto def; } return 3; }
default: { def: return -1; }
}
}
which might indeed be less verbose with MACRO
#define CaseHash(str, c) case myhash(c): if (str != c) { goto def; }
#define DefaultHash default: def
to result to
constexpr std::size_t myhash(std::string_view) { /* .. */ }
int foo(const std::string& tag)
{
switch (tag)
{
CaseHash(tag, "a") { return 1; }
CaseHash(tag, "b") { return 2; }
CaseHash(tag, "abc") { return 3; }
DefaultHash: { return -1; }
}
}

Can this get to the end of the function and not return anything?

I am making a c++ text based game and while making a feature for eating food I made this function names eating. I am getting a warning saying its possible to reach the end with no return value. How is it possible to get to the end and not return something?
int inventory::eat(std::string eating)
{
if (!consumables.empty())
{
for (int i = 0; i < consumables.size(); i++)
{
if (consumables[i].name == eating)
{
return consumables[i].effect;
}
else
{
return 404;
}
}
}
else
{
return 505;
}
}
Presumably the compiler is unable to tell that if consumables.empty() == false, then consumables.size() > 0.
I'd probably rewrite it as this, but I'm worried about the if/else inside your for loop.
int inventory::eat(std::string eating) {
for (int i = 0; i < consumables.size(); i++) {
if (consumables[i].name == eating) {
return consumables[i].effect;
} else {
return 404;
}
}
return 505;
}
Assuming no other thread modifies consumables while eat() is running, then no, return will not be skipped. But the compiler doesn't know that. It doesn't knower that !empty() and size() > 0 mean the same thing for a container. They are just two separate method calls.
That said, I would suggest writing the code more like this, which is easier to read, and avoids the warning:
int inventory::eat(const std::string &eating)
{
if (consumables.empty())
return 505;
for (int i = 0; i < consumables.size(); ++i)
{
if (consumables[i].name == eating)
return consumables[i].effect;
}
return 404;
}
Or, if you are using C++11 and consumables supports iterators:
#include <algorithm>
int inventory::eat(const std::string &eating)
{
if (consumables.empty())
return 505;
auto found = std::find_if(
consumables.begin(), consumables.end(),
// replace 'consumable' below with your actual type name as needed...
[&](const consumable &c){ return c.name == eating; }
);
if (found != consumables.end())
return found->effect;
return 404;
}

Templates in main ( I know it shouldnt be there)

Well, basically for a class I need to make a simple program that used templates, in which I receive data from the user that I dont really know the type of, until I receive it.
template <typename T>
int main()
{
Calculator<T> calc;
bool flag = true;
int punto = 0;
string entry, op;
T a, b, r;
entry = ' ';
while (flag) {
try {
cin << op;
entry += op;
for (int i = 0; i < entry.length(); i++) {
if (entry[i] == '+' || entry[i] == '-' || entry[i] == '*' || entry[i] == '/') {
for (int j = 0; j < i; j++) {
if (entry[j].isdigit) {
a += entry[j];
}
else if (entry[j] == '.') {
a += entry[j];
punto++;
if (punto > 1) {
throw '.';
}
}
else{
throw "l";
}
}
if (punto = 1) {
a = stof(a);
}
else {
a = stoi(a);
}
I know the problem is the template part at the start, but sice I need to change the type a couple types I dont really know what to do. Obviusly because of the template it doesnt detect my main() fuction as main and is giving me the "Header Errors LNK2019"
This does not work because the linker fails to find main. Also, it doesn't make sense because you can only run main once, and you ought to know which type T has at any given invocation. :-)
If you just want to use T as a placeholder, you use a typedef declaration (or an equivalent using declaration) like this:
int main() {
using T = int;
Calculator<T> calc;
// rest of code here
// ...
}

How to limit a decrement?

There is a initial game difficulty which is
game_difficulty=5 //Initial
Every 3 times if you get it right, your difficulty goes up to infinity but every 3 times you get it wrong, your difficulty goes down but not below 5. So, in this code for ex:
if(user_words==words) win_count+=1;
else() incorrect_count+=1;
if(win_count%3==0) /*increase diff*/;
if(incorrect_count%3==0) /*decrease difficulty*/;
How should I go about doing this?
Simple answer:
if(incorrect_count%3==0) difficulty = max(difficulty-1, 5);
But personally I would wrap it up in a small class then you can contain all the logic and expand it as you go along, something such as:
class Difficulty
{
public:
Difficulty() {};
void AddWin()
{
m_IncorrectCount = 0; // reset because we got one right?
if (++m_WinCount % 3)
{
m_WinCount = 0;
++m_CurrentDifficulty;
}
}
void AddIncorrect()
{
m_WinCount = 0; // reset because we got one wrong?
if (++m_IncorrectCount >= 3 && m_CurrentDifficulty > 5)
{
m_IncorrectCount = 0;
--m_CurrentDifficulty;
}
}
int GetDifficulty()
{
return m_CurrentDifficulty;
}
private:
int m_CurrentDifficulty = 5;
int m_WinCount = 0;
int m_IncorrectCount = 0;
};
You could just add this as a condition:
if (user words==words) {
win_count += 1;
if (win_count %3 == 0) {
++diff;
}
} else {
incorrect_count += 1;
if (incorrect_count % 3 == 0 && diff > 5) {
--diff
}
}
For example:
if(win_count%3==0) difficulty++;
if(incorrect_count%3==0 && difficulty > 5) difficulty--;
This can be turned into a motivating example for custom data types.
Create a class which wraps the difficulty int as a private member variable, and in the public member functions make sure that the so-called contract is met. You will end up with a value which is always guaranteed to meet your specifications. Here is an example:
class Difficulty
{
public:
// initial values for a new Difficulty object:
Difficulty() :
right_answer_count(0),
wrong_answer_count(0),
value(5)
{}
// called when a right answer should be taken into account:
void GotItRight()
{
++right_answer_count;
if (right_answer_count == 3)
{
right_answer_count = 0;
++value;
}
}
// called when a wrong answer should be taken into account:
void GotItWrong()
{
++wrong_answer_count;
if (wrong_answer_count == 3)
{
wrong_answer_count = 0;
--value;
if (value < 5)
{
value = 5;
}
}
}
// returns the value itself
int Value() const
{
return value;
}
private:
int right_answer_count;
int wrong_answer_count;
int value;
};
And here is how you would use the class:
Difficulty game_difficulty;
// six right answers:
for (int count = 0; count < 6; ++count)
{
game_difficulty.GotItRight();
}
// check wrapped value:
std::cout << game_difficulty.Value() << "\n";
// three wrong answers:
for (int count = 0; count < 3; ++count)
{
game_difficulty.GotItWrong();
}
// check wrapped value:
std::cout << game_difficulty.Value() << "\n";
// one hundred wrong answers:
for (int count = 0; count < 100; ++count)
{
game_difficulty.GotItWrong();
}
// check wrapped value:
std::cout << game_difficulty.Value() << "\n";
Output:
7
6
5
Once you have a firm grasp on how such types are created and used, you can start to look into operator overloading so that the type can be used more like a real int, i.e. with +, - and so on.
How should I go about doing this?
You have marked this question as C++. IMHO the c++ way is to create a class encapsulating all your issues.
Perhaps something like:
class GameDifficulty
{
public:
GameDifficulty () :
game_difficulty (5), win_count(0), incorrect_count(0)
{}
~GameDifficulty () {}
void update(const T& words)
{
if(user words==words) win_count+=1;
else incorrect_count+=1;
// modify game_difficulty as you desire
if(win_count%3 == 0)
game_difficulty += 1 ; // increase diff no upper limit
if((incorrect_count%3 == 0) && (game_difficulty > 5))
game_difficulty -= 1; //decrease diff;
}
inline int gameDifficulty() { return (game_difficulty); }
// and any other access per needs of your game
private:
int game_difficulty;
int win_count;
int incorrect_count;
}
// note - not compiled or tested
usage would be:
// instantiate
GameDiffculty gameDifficulty;
// ...
// use update()
gameDifficulty.update(word);
// ...
// use access
gameDifficulty.gameDifficulty();
Advantage: encapsulation
This code is in one place, not polluting elsewhere in your code.
You can change these policies in this one place, with no impact to the rest of your code.

Changing while loop to accommodate two situations

Suppose I have a while loop that depends on two separate inputs. In situation one, the while loop will take the value 1, and in situation two, it should take !cin.eof(). Is there a way I can do this efficiently? To be more concise:
string hello;
cin >> hello;
if(hello == "one")
{
//make the while loop depend on value 1
}
else if(hello == "two")
{
//make the while loop depend on value !cin.eof()
}
while(/*depends on above conditional*/)
{}
I don't want to do something like:
if(hello == "one)
{
while(1){}
}
else if(hello == "two")
{
while(!cin.eof){}
}
because the while loop essentially does the same thing in each situation.
For readability and in the interest of cohesion, I think you should move the contents of your loop into a separate function:
void DoSomething() { /* ... */ }
// ...
if(hello == "one)
{
while(1){ DoSomething(); }
}
else if(hello == "two")
{
while(!cin.eof){ DoSomething(); }
}
It's easier to see that the different while loops are doing the same thing but their conditions are different.
I believe you're looking for something like this:
while((hello == "one") || (hello == "two" && !cin.eof)) {
}
This code will do what you want, because it checks 'is the variable "one"? If so, keep executing. If it's not, it'll check: Is the variable "two"? If so, it'll check for cin.eof.
If it's neither, the loop won't execute. (the && 1 in the first condition was omitted, because it's always 'true', equalling and infinite loop)
Edit:
To simplify things, you may want to consider this code (as suggested in the comments):
bool HelloIsOne = (strcmp(hello, "one") == 0);
bool HelloIsTwo = (strcmp(hello, "two") == 0);
while(HelloIsOne || HelloIsTwo && !cin.eof) {
}
The brackets, which I placed in the previous example are actually unnecessary, because && binds stronger than ||, but they help the general clarity of the code.
Simply use or (||) as a condition in the while loop. Set the first condition if(hello == "one"). Now you have a while loop that will loop if one of the conditions is true.
bool value = hello == "one";
while (value || !cin.eof) {}
If you're using C++11:
#include <functional>
auto check = (hello == "one") ? []() bool -> { return 1; } :
[]() bool -> { return !cin.eof(); };
while(check) {
};
How about this:
switch(hello)
{
case 'one':
{
for(; 1; );
{
// your loop here
}
break;
}
case 'two':
{
for(;!cin.eof; )
{
// your other loop here
}
break;
}
default:
{
cout << " shouldnt get here unless bad user input" << endl;
break;
}
}
You can do something like this:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string hello;
cin >> hello;
while(hello=="one"?1:(!cin.eof()))
{
//do stuff
}
return 0;
}
It checks if the string hello is "one" and if it's true, the condition of the while is 1, else it is !cin.eof() as you wanted.