fergu
fergu

Reputation: 329

Call a function based on string input

I guess this could be described as a "plug in architecture" problem.

At the moment I have a code written in c++ which needs to call a specific function (a fitness function in an optimization routine). Previously, this has required a lot of duplication of code, which has made maintaining as I've discovered bugs a nightmare. So - I have managed to condense the code such that I have only one of everything except for the various fitness functions, which obviously cannot be condensed.

These fitness functions do not share a name, nor do they need to. The way that I have it set up is that the optimization routine calls one "main" fitness function, which performs a string comparison between an input string and a hardcoded "name" for the function. I.E:

FitFunc myMainFit(double* inp, int d) {
    double retVal;
    if (inName == "func1") {
        retVal = myFitOne(inp, d);
    } else if (inName == "func2") {
        retVal = myFitTwo(inp, d);
    // Other comparisons ...
    } else {
        std::cout << "Unknown Function" << std::endl;
        retVal = -1;
    }

    return retVal;
}

What I'd like to do is have a way to dynamically create these comparisons so that I don't have to update a bunch of things every time I have a new function that I want to use.

At the moment, my fitness functions are all in one directory, and share some common naming characteristics, including having the same name as the function they contain. I.E - myFitTwo.cpp contains myFitTwo(double*, int)

My thought was that I could add a step to my makefile to generate the above block of code at compile time, as well as the requisite function definitions in an included hpp file.

Is this the best way to go about this? Is there a better way, or is the best option just to continue as I have been and add the functions manually as I create them? I'm not creating a huge number of these, nor am I creating them terribly frequently, but automating the process feels less prone to error. I'd also like to be able to give this code to a coworker, and would like him to be able to add functions without having to muck around in the rest of the files.

Upvotes: 0

Views: 3336

Answers (1)

vsoftco
vsoftco

Reputation: 56547

You can use a std::map<std::string, FUNCPTR>, where FUNCPTR is an alias for the function pointer. Example:

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

typedef void(*FUNCPTR)(double*, int); // our typedef
std::map<std::string, FUNCPTR> func_map;

// some functions
void f1(double*, int) {std::cout << "f1" << std::endl;}
void f2(double*, int) {std::cout << "f2" << std::endl;}

// call them via an invoking function
void myMainFit(const std::string& which, double* ptr, int val)
{
    if(func_map.find(which)!= func_map.end()) // indeed the function was added
        func_map[which](ptr, val);
    else
    {
        std::cerr << "Function \"" << which << "\" is not in the map!\n";
        return; // or throw
    }
}

int main()
{
    // add functions to the map
    func_map["first"] = &f1;
    func_map["second"] = &f2;
    myMainFit("first", nullptr, 42);
    myMainFit("second", nullptr, 20);
    myMainFit("inexistent", nullptr, 10);
}

Live on Ideone

As mentioned by @David Haim, you can use std::unordered_map (C++11) to speed things up, as the latter is a hash table, and it has amortized O(1) access time.

Upvotes: 3

Related Questions