Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Changing return type of a function without template specialization. C++

I was wondering if it is possible to change the return type of a function based on the type of variable it is being assigned to. Here's a quick example of what I mean.

I want to create a function that parses a variable of int, bool, or float from a string. For example...

Int value = parse("37");
Float value = parse("3.14");
Bool value = parse("true");

I understand if I make this function a template, that the variable type must be determined from the argument list which is always going to be a string. Is there any other way of doing this with c++?

like image 571
Morgan Avatar asked Jun 18 '09 02:06

Morgan


3 Answers

This can be done with a conversion function

struct proxy {
    string str;
    proxy(string const &str):str(str) { }
    template<typename T> operator T() { 
        return boost::lexical_cast<T>(str); 
    }
};

proxy parse(string const &str) { return proxy(str); }

Now you just need to do

float a = parse("3.1");

And it should work well. Incidentally, you may just use the class directly. I recommend renaming it to conversion_proxy to point to the fact that it's just a proxy to a happening conversion but that it itself doesn't do conversion

struct conversion_proxy {
    string str;
    conversion_proxy(string const &str):str(str) { }
    template<typename T> operator T() { 
        return boost::lexical_cast<T>(str); 
    }
};

float a = conversion_proxy("3.1"); 
like image 130
Johannes Schaub - litb Avatar answered Nov 08 '22 11:11

Johannes Schaub - litb


I can't tell from your question if you know this or not, but you can indeed do this with a template. The only catch is that you will have to specify the type that you are converting from in each invocation instead of relying on inference (since as you said the argument type will always be the same).

template<typename T> T parse(const string& str) { /* do stuff for other types */ }
template<> int parse<int>(const string& str) { /* do stuff for ints */ }
template<> double parse<double>(const string& str) { /* do stuff for doubles */ }
template<> bool parse<bool>(const string& str) { /* do stuff for bools */ }
// etc.

And then invoke as

int value = parse<int>("37");
double value = parse<double>("3.14");
bool value = parse<bool>("true");

If you already knew this just ignore this answer, but it's not clear from your question that you are aware that this is possible.

Of course, if what you're doing isn't really generic (and so you have to specialize for each type you want to parse) then writing a template isn't the right thing to do anyway.

By the way, you can do it pretty generically with a single function like this (assuming parse is what you really want to do):

#include <sstream>
template<typename T> T parse(const string& str) 
{
  T t;
  std::istringstream sstr(str);
  sstr >> t;
  return t;
}

This will work for any default-constructable, stream-extractable type, which includes all built-ins.

like image 12
Tyler McHenry Avatar answered Nov 08 '22 13:11

Tyler McHenry


You could pass your output argument as a pointer or reference.

Like this:

template<class T> void parse(const std::string &input, T& output);

Then code like this:

double d; parse(input, d);
int i; parse(input, i);

should work.

However, your code looks like a perfect fit for an std::istringstream that would just be:

istringstream is(input);
input >> d;

If you have somewhat complicated formatting involved, a trick I have had pretty good luck with involves creating custom objects with custom operator>> that pulls out data.

Then it could be like:

istringstring is(input);
input >> LineExtracter(x, y, d);
like image 5
Zan Lynx Avatar answered Nov 08 '22 13:11

Zan Lynx