Friday, November 15, 2013

C++ and dynamic datatype at run-time

Recently I was working on C++ code that had bunch of if-else statements that resembled following. As you can see there is common code however datatype of couple of variables varies based on the condition.
std::string type = get_type();
if (type == "int") {
UParamInt p;
.....
.....
int v;
.....
.....
} else if (type == "float") {
UParamFloat p;
.....
.....
float v;
.....
.....
} else if (type == "bool") {
UParamBool p;
.....
.....
bool v;
.....
.....
} else if (type == "string") {
UParamString p;
.....
.....
string v;
.....
.....
}
view raw ifelseblock.cpp hosted with ❤ by GitHub

You can see the pattern here! So moved the common code to a function template of the form
template<typename T, typename U>
int process_param(void)
{
T p;
.....
.....
U v;
.....
.....
}

So far so good. However in order to invoke the right function I still needed to use if-else block which was an eye-sore
if (type == "int") {
process_param<UParamInt, int>();
} else if (type == "float") {
process_param<UParamFloat, float>();
} else if {
....
}

To avoid if-else block, I decided to use a jump-table using map where key would be datatype (string) and value would be function to be invoked.
typedef int (*ProcessParamFuncPtr)(void);
typedef std::map< std::string, ProcessParamFuncPtr> ProcessFuncMap;
// Initialize map with appropriate functions for the datatype.
ProcessFuncMap map = boost::assign::map_list_of
("int64", process_param< UConfigParamInt, int >)
("bool", process_param< UConfigParamBool, bool >)
("float", process_param< UConfigParamFloat, float >)
("string", process_param< UConfigParamString, std::string>);
// Invoke function based on the datatype
std::string type = get_type();
ProcessFuncMap::iterator it = map.find(type);
if (it != map.end()) {
ProcessParamFuncPtr fptr = (*it).second;
int ret = fptr();
}
view raw jumptable.cc hosted with ❤ by GitHub

In addition to UConfigParam type variables, I needed to add support for other variables of the form UStateVar. To achieve this, I simply added more entries to the ProcessFuncMap without changing code for function invocation or piling up if-else code block.

So there you see, using a combination of function templates and a jump table at run time dynamic declaration of variables is achievable.

If there are known design patterns or other techniques that help achieve same in C++ I'd like to hear about them.