Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I templatize a function without repeating code but only changing the parsing function?

Tags:

c++

templates

I have an existing function that converts a comma-delimited string of numbers into a vector, e.g. "1,2,3" becomes [1,2,3]

The function looks very roughly like:

bool ConvertStringToNumberList(string input, vector<int32_t>& output)
{
  <bunch of code>
  int32_t value = strtol(str, 0, /*base*/ 10);
  <bunch of code>
}

I would like to change this into a template function that will work for int32_t, uint32_t, double, and float.

The problem is that, for each data type, there is a different parsing function (e.g. strtol, strtoul, strtod, strtof) that may take different number of parameters (e.g. strtod() does not take a "base" parameter).

How can I templatize the above code without repeating the <bunch of code> but only changing the parsing function?

like image 657
jfritz42 Avatar asked Mar 18 '23 19:03

jfritz42


2 Answers

Just create the class which will have specializations, each with a static function to parse one of the types you want to support and use it from your function template.

E.g.:

template <typename T>
struct Converter {};

template <>
struct Converter<int32_t> {
   static int32_t Parse(const std::string& str) {
      return strtol(str, 0, /*base*/ 10); 
   }
};

template <>
struct Converter<double> {
   static double Parse(const std::string& str) {
      return atof(str); 
   }
};

template <typename T>
bool ConvertStringToNumberList(string input, vector<T>& output) {
  // <bunch of code>
  T value = Converter<T>::Parse(str);
  // <bunch of code>
}

Alternatively, you may have plain Parse function, which has overloads for each type, but there you may get unexpected type promotions.

like image 137
Krizz Avatar answered Mar 21 '23 08:03

Krizz


Unless you really want to do the whole job yourself, you're probably best off using something other than strtol to start with. One possibility that would fit pretty nicely here would be boost::lexical_cast:

template <class T>
ConvertStringToNumberList(string input, vector<T> &output) { 
    <bunch of code>
    T value = boost::lexical_cast<T>(str);
    <bunch more code>
}

lexical_cast is pretty much equivalent to stuffing the string into a stringstream, then reading out the specified type, but it provide overloads to optimize for many of the most common types, so in many (most?) typical cases, it's quite a bit faster.

like image 30
Jerry Coffin Avatar answered Mar 21 '23 08:03

Jerry Coffin