Function, lambda, and switching on strings

Ambreen H.
2 min readApr 26, 2020

In the same spirit as that of my last post, I found myself needing to compare strings that my hobby project is receiving on command line arguments and to take specific actions based on what was passed.

The usual if-else statement felt like a lot of typing and I thought why not just use lambdas to dictate what needs to be done and use the unordered_map to match the string and execute the appropriate lambda.

Ergo, I got started on this task. I know I need a hash map of a sort and although in C++, keys don’t need to be string, given my current needs, I went with std::string. Now, there is the question of how to associate the lambdas as values, and that’s where std::function comes into play.

Encapsulating the behavior

I also want to tie everything together, So I went with a struct.

struct Switch {
using void_function = std::function<void(void)>;
std::unordered_map<std::string, void_function> cases;
...
Switch() {}
};

Now comes the part of populating the hash map and that’s below:

void add_case(std::string const & key, void_function func) {
cases[key] = func;
}

Now, I want to be able to just do this and execute the correct flow:

Switch s;
// adding some cases
...
s(to_switch_on)

For that, I’m going to overload the call operator and have it take the key as an input parameter:

void operator()(std::string const & key) {
...
}

Now, I have two tasks, check if the key exists, if it does execute the function associated with it. If not, check if any key is set for ‘default’ case (because why not), otherwise for the time being, just print an error. I could later in the future, throw an exception, in such a situation.

void operator()(std::string const & key) {
auto f = cases.find(key);
f = (f == cases.end()) ? cases.find("default") : f;
if (f == cases.end()) {
std::cout << "Case not found and default not set\n";
return;
}
f->second();
}

Using the string switcher

Okay, with that much done so far. I could, for example, use this struct as follows:

std::string message = "c'est la vie";Switch s;
s.add_case("", [&message](void) {
std::cout << message << std::endl;
});

s.add_case("d", [msg="cogito ergo sum"]{
cout << msg << endl;
});
s("live_your_life");
s("i_think_therefore_i_am");
s("not_existing_key");

Output for that would be:

c'est la vie
cogito ergo sum
Defaul switch case

In my hobby project, I collapsed the if-else-if as follows:

Switch s;
s.add_case("projects",[&]{this->showProjects();});
s.add_case("add", [&]{this->addProjects(arguments); });
s.add_case("latest", [&]{this->showLatest(arguments)});
s.add_case("time", [&]{this>startTimer(arguments)});
s.add_case("stop", [&]{this->stopTimer(arguments); });
s.add_case("today", [&]{this->showTimeSpentToday(arguments);});
s(command);

--

--