11

Can you call a function depending on which number an integer is?

Here's what I mean:

#include <iostream>

using namespace std;

int whichFunction;

int main()
{
    cout << "Which function do you want to call?";
    cin >> whichFunction;

    function[whichFunction](); 
    //If you entered 1, it would call function1 - same with 2, 3
    //or Hihihi (of course only when whichFunction would be a string)
}


void function1()
{
    cout << "Function No. 1 was called!";
}

void function2()
{
    cout << "Function No. 2 was called!";
}

void functionHihihi()
{
    cout << "Function Hihihi was called!";
}

I know this doesn't work but I hope you get the idea.

So is there a way to do something like that?

Rakete1111
  • 47,013
  • 16
  • 123
  • 162
TPRammus
  • 491
  • 1
  • 6
  • 19

5 Answers5

19

Yes, there is a way to do that.

//Array for the functions
std::array<std::function<void()>, 3> functions = { &function1, &function2, &function3 };

//You could also just set them manually
functions[0] = &function1;
functions[1] = &function2;
functions[2] = &function3;

Then you can use it as a normal array:

functions[whichFunction](); //Calls function number 'whichFunction'

Do note that the functions all have to have the same signature.


If you do not want to use std::function for some reason, you can use function pointers.

Community
  • 1
  • 1
Rakete1111
  • 47,013
  • 16
  • 123
  • 162
13
switch(whichFunction) {
    case 1: function1(); break;
    case 2: function2(); break;
    case 3: function3(); break;
}
Pete Becker
  • 74,985
  • 8
  • 76
  • 165
  • This is much better than all the function pointer (or worse) solutions – M.M Sep 11 '16 at 12:50
  • @M.M: uhum, that's your opinion. Now, what if user wants to replace `function2()` with `function2a()` in the 'array' in the middle of the code, based on `rand() % 2`? – lorro Sep 11 '16 at 13:24
  • @lorro `case 2: if ( rand() % 2 ) function2a(); else function2(); break;` – M.M Sep 11 '16 at 13:28
  • @M.M: what I tried to say is, I want it to be a state whether I'll choose `function2()` or `function2a()`. By putting a `switch` here, you're repeating the state that you have somewhere else (perhaps in a class). – lorro Sep 11 '16 at 13:32
  • @lorro no idea what you are talking about, there is no need to repeat elsewhere – M.M Sep 11 '16 at 14:49
  • @M.M: what I'm saying is, with the array-based version, you can replace the function with another one runtime. Here, you need to put in the logic for that. – lorro Sep 11 '16 at 20:53
  • @lorro OK, fair enough. I guess it will come down to whether OP needs that as a requirement. – M.M Sep 11 '16 at 22:28
5

use pointer to function is a good thing:

#include <iostream>
#include <string>
using namespace std;


void foo1(){cout << "Foo1 says hello!" << endl;}
void foo2(){cout << "Foo2 says hello!" << endl;}
void foo3(){cout << "Foo3 says hello!" << endl;}
void foo4(){cout << "Foo4 says hello!" << endl;}


int main()
{

    system("color 1f");

    int input;
    cout << "Which function you wanna call: ";
    cin >> input;
    cout << endl;


    void (*pFunc)() = NULL;

    switch(input)
    {
        case 1:
            pFunc = foo1;
        break;
        case 2:
            pFunc = foo2;
        break;
        case 3:
            pFunc = foo3;
        break;
        default:
            cout << "No function available!" << endl;
    }

    if(NULL != pFunc) //avoiding usage of a NULL ptr
        (*pFunc)();

    cout << endl << endl << endl;
    return 0;
}
Raindrop7
  • 3,889
  • 3
  • 16
  • 27
  • This is essentially the same as an `if` cascade, which OP stated he wishes to avoid. – adnan_e Sep 11 '16 at 12:15
  • @adnan_e: if you use only if and wants to call the function once it's then ok. but what if you want to call that function x times later on depending on the Precedent input??? so you need to switch again and again!! it's tiresome. so instead store the function address in a pointer to function do switch once and everytime you want to call it depending on the last input it's ok use the pointer – Raindrop7 Sep 22 '16 at 12:21
  • I didn't say you are right nor wrong, I stated that OP said he's looking for a *different* way. – adnan_e Sep 22 '16 at 21:23
3

Support for string input:

std::map<std::string, std::function<void()>> le_mapo;
le_mapo["1"] = &function1;
le_mapo["2"] = &function2;
le_mapo["3"] = &function3;
le_mapo["Hihihi"] = &functionHihihi;

std::string input;
std::cin >> input;

auto check = le_mapo.find(input);

if (check != le_mapo.end()) 
{
    le_mapo[input](); //call function
}
else
{
    //not found
}

Too long to write? Prepare for storm!

#define BE_EVIL(map, function, x) map[ #x ] = & function ## x
//custom macro with predefined function name (here: just function)
#define BE_EVIL_FUN(map, x) BE_EVIL(map, function, x)
//same, with predefined map name
#define BE_EVIL_JUST_X(x) BE_EVIL_FUN(le_mapo, x)

And use:

//"connect" string to function
BE_EVIL(le_mapo, function, 1); //le_mapo[ "1" ] = & function1;
xinaiz
  • 7,744
  • 6
  • 34
  • 78
  • 1
    You can use **initialization list** rather than assignment to each item. No need for EVIL and even shorter! – JDługosz Sep 11 '16 at 18:46
1

You can use the polymorphism concept (via virtual functions and inheritance).

Here is a very basic scheme:

#include <iostream>
#include <vector>

using namespace std;

class Obj
{
public:
    virtual void function() = 0;
};

class Obj1 : public Obj
{
public:
    virtual void function() {cout << "Function No. 1 was called!";}
};

class Obj2 : public Obj
{
public:
    virtual void function() {cout << "Function No. 2 was called!";}
};

class Obj3 : public Obj
{
public:
    virtual void function() {cout << "Function No. 3 was called!";}
};

int main()
{
    vector<Obj*> objects;
    objects.push_back(new Obj1);
    objects.push_back(new Obj2);
    objects.push_back(new Obj3);

    cout << "Which function do you want to call?";
    int whichFunction;
    cin >> whichFunction;
    if (1 <= whichFunction && whichFunction <= objects.size())
        objects[whichFunction-1]->function();

    for (auto object : objects)
        delete object;

    return 0;
}
barak manos
  • 29,648
  • 10
  • 62
  • 114
  • 1
    Wow, this is one horrible approach for such a simple task. Also, deleting objects of abstract class type wich don't have virtual destructors causes U.B. – adnan_e Sep 11 '16 at 13:40
  • @adnan_e: Such a simple task doesn't require function pointers at all. I am assuming that OP has asked that in order to get a general idea for something a lot more complicated. – barak manos Sep 11 '16 at 13:41
  • Yea, you are inventing a plain pointer to function by using virtual calls and a new class for each needed value. There are advantages to using *types* and knowing which is used at compile time, but a template would be better. – JDługosz Sep 11 '16 at 18:44
  • 1
    @JDługosz: Putting aside the rudeness expressed in your comment, a virtual function is essentially a function pointer (resolved only during runtime, in opposed to a non-virtual function, which is resolved during compilation). – barak manos Sep 12 '16 at 05:59