user3176017
user3176017

Reputation: 103

using command line input to call a function

I'm building a set of functions in an included file, and i would like to be able to run my test main() to call the function name passed on the command line. Something like this:

void rotate (int degrees) {
    /*...*/
}

void translate (int pixels) {
    /*...*/
}

int main(int argc, char* argv[] ) {
    const int degs = 100;
    const int pix = 250;

    string func = argv[1];
    //call func(degs) or func(pix) based on the command line argument passed
}

I'd like to be able to run this like % a.out translatefrom the command line. What is the syntax to make this work. Thanks in advance I looked for a while on this one and couldn't find anything.

Upvotes: 2

Views: 6607

Answers (3)

Veritas
Veritas

Reputation: 2210

As you requested, here is an example on how you could use std::map to achieve what you want. I am using void functions with void parameters for the sake of simplicity. In your case, you will have to use void (*)(int) for the map in order to use your functions since they take ints as parameters. You will also have to find how to pass the ints themselves. You can probably do this by taking the argv arguments by pairs.

#include <iostream>
#include <map>
#include <string>

void func1() {
    std::cout << "func1" << std::endl;
}

void func2() {
    std::cout << "func2" << std::endl;
}

void func3() {
    std::cout << "func3" << std::endl;
}

std::map<std::string,void (*)(void)> tmap = {
    {"func1",&func1},
    {"func2",&func2},
    {"func3",&func3}                        
};

int main(int argc, char* argv[]) {
    if (argc > 1) {
        for (int i =1; i != argc; ++i) {
            if (tmap.find(argv[i]) != tmap.end()) {
                tmap[argv[i]]();
            }
            else {
                std::cout << "There is no " << argv[i] << " function available." << std::endl;
             }
         }
    }
    else {
        std::cout << "No functions were choosen." << std::endl;
    }
    return 0;
}

Upvotes: 3

M.M
M.M

Reputation: 141574

As requested...

#include <iostream>
#include <string>
#include <map>

typedef void FUNC(int); 

FUNC rotate, translate;

int main(int argc, char *argv[])
{
    std::map<std::string, FUNC *> m;
    m["rotate"] = rotate;
    m["translate"] = translate;   

    if ( argc > 1 )
    {
        FUNC *ptr = m[argv[1]];
        if ( ptr )
            ptr(100);
    }
}

In C++11 you can use brace-enclosed initializers for m.

If the duplication bothers you, you could even go:

#define M_ROW(funcname) m[#funcname] = funcname

Upvotes: 2

Mats Petersson
Mats Petersson

Reputation: 129374

It is not possible to do this in C or C++, because the name of the function "disappears" when you compile the code.

The common way to solve this is to use either a std::map<std::string, FunctionPtr> or some other form of table that contains a translation between string and function pointer.

Of course a very crude version is to simply do:

if (argv[1] == std::string("translate"))
{
    int x = atoi(argv[2]);
    translate(x);
}

(You need the cast to std::string or you need to use strcmp, since using == between a char * and a string literal will just compare the address of the string, and argv isn't going to contain addresses of string literals under any reasonable circumstances)

Function pointers in std::map could be something like this

typedef void (*FuncType)(int v);

std::map<std::string, FuncType> m;

m["translate"] = translate;
m["rotate"]    = rotate;

// Convert argv[2] to integer:
int x = argv[2];
// Call function indicated by argv[1]:
m[argv[1]](x);

Upvotes: 6

Related Questions