How to customly convert template arguments - c++

Lets say I parse a file and will get a string vector as a result which contains various data types. I'm now looking for a function like:
template<typename T>
T convertToType(const std::string& str);
which can do this conversion. Ideally I should be able to somehow provide my own conversion function, i.e. if T is an own complex type. Is there a way around having to pass it as a parameter everytime?
I was thinking about some sort of:
if(typeof(T) == double)
std::stod(str)
// ...
else
throw std::logical_error("Type not supported yet!");
Another option would be to write a template specialization for each type but this seems to make the use of a template function pretty useless if I have to specify it for each type again...

This is turning Joachim's comment into an answer.
Use std::istringstream and let the input operator >> handle it.
std::istringstream iss(str);
T result;
if (!(iss >> result)) {
throw std::logical_error("Type conversion failed!");
}
return result;

Related

Is there a function similar to stoi that would work for a template class?

I've created a class for complex numbers for an assignment last week and our next assignment is to modify this class to be a template class. Part of the assignment was overloading the extraction operator, and originally when only dealing with int, I took the whole input line as a string and made substrings for the real and imaginary parts, then I used stoi to convert the parts to ints which I could store (This is what my professor suggested doing). However, now that this is is a template class stoi no longer works if the type being used is double, float, etc. Is there a function that works similarly but across different types? Or possibly another solution altogether that may work better?
I tried using if statements to detect what type is being used and then using stoi, stod, etc. accordingly however, this seems less than ideal because it only works for the types I explicitly define, and I'm sure this isn't what they're looking for.
template <class T>
istream& operator>>(istream& in,MyComplex<T> &num){
string inString;
getline(in, inString);
T test = 3.33;
if(test != 3.33){
//convert using stoi
}
else if(test == 3.33){
//convert using stod
}
//etc.
}
I left out what's inside the brackets because it's very long and doesn't change the fact that I can only define for a finite amount of data types. Thank you in advance for any help!
I would recommend using the input stream directly. It seems like your input format is 2.3 + 5i, so you can use the following code:
double a,b;
char c;
in >> a >> c >> b; // c eats the +; let's the i in the in
in >> c; // eats the i
Note that then we also can use c two times in the same line, I just wanted space for my comments so I put it on the next.
A more general note to your code:
The "right" way to check what type T is (or maybe just what attributes the type has, since you probably don't need to differentiate between say int and long), is to use type traits.
But, for having completely different implementations for different types, you should use different implementations, so declare a method that takes MyComplex<double>, one that takes MyComplex<int>, etc.

Piping from Istringstream into templates

I have the following questions: I have a map from string to string which is called psMap. I.e. psMap["a"]="20", psMap["b"]="test", psMap["c"]="12.5", psMap["d"]="1" (true) so the map stores string-expressions of various basic-data types.
The following function foo should (given a key), copy the mapped value to a corresponding type variable, i.e;
int aa;
foo("a", aa);
=> aa=20.
Explicitly, I want to have one function for all possible data-types (so no manually cast), so I tried with templates exploiting the automatic conversion of istringsteram, namely
template<class PARAMTYPE>
void foo(string _name, PARAMTYPE& _dataType) {
PARAMTYPE buff;
istringstream(psMap[_name]) >> buff;
_dataType = buff;
}
The problem is, that the ">>" operation gives an error: Error: no match for »operator>>« in »std::basic_stringstream<char>((* ....
What is going wrong here? Does the stringstream not recognize the correct data type and tries to pipe into an abstract type of "template"? How could I make my code work?
Tank you for your effort :)
You've created a temporary std::istream, which means that it
cannot bind to a non-const reference. Some of the >> are
member functions, and they will work, but others are free
functions with the signature:
std::istream& operator>>( std::istream&, TargetType& );
and these will not work (or even compile).
To avoid the problem either Just declare an std::istringstream
and use it, or call a member function on the temporary which
does nothing, but returns a (non-const) reference:
std::istringstream( psMap[name] ).ignore(0) >> buff;
(Personally, I find the separate variable more readable.)
You use reference as the template argument, so if you call
foo("a", aa);
without '& it should be fine (the way you tried the operator>> for pointer was needed). You also need to modify the last template line:
_dataType = buff;
Try this implementation:
template<class R>
R get_value(const std::string& name) {
R result{};
std::istringstream buffer{psMap[name]};
buffer >> result;
return result;
}
client code:
int x = get_value<int>("a");
Also, do not use identifiers starting with an underscore. That is reserved for library implementers.

Using templates for implementing a generic string parser

I am trying to come up with a generic solution for parsing strings (with a given format). For instance, I would like to be able to parse a string containing a list of numeric values (integers or floats) and return a std::vector. This is what I have so far:
template<typename T, typename U>
T parse_value(const U& u) {
throw std::runtime_error("no parser available");
}
template<typename T>
std::vector<T> parse_value(const std::string& s) {
std::vector<std::string> parts;
boost::split(parts, s, boost::is_any_of(","));
std::vector<T> res;
std::transform(parts.begin(), parts.end(), std::back_inserter(res),
[](const std::string& s) { return boost::lexical_cast<T>(s); });
return res;
}
Additionally, I would like to be able to parse strings containing other type of values. For instance:
struct Foo { /* ... */ };
template<>
Foo parse_value(const std::string& s) {
/* parse string and return a Foo object */
}
The reason to maintain a single "hierarchy" of parse_value functions is because, sometimes, I want to parse an optional value (which may exist or not), using boost::optional. Ideally, I would like to have just a single parse_optional_value function that would delegate on the corresponding parse_value function:
template<typename T>
boost::optional<T> parse_optional_value(const boost::optional<std::string>& s) {
if (!s) return boost::optional<T>();
return boost::optional<T>(parse_value<T>(*s));
}
So far, my current solution does not work (the compiler cannot deduce the exact function to use). I guess the problem is that my solution relies on deducing the template value based on the return type of parse_value functions. I am not really sure how to fix this (or even whether it is possible to fix it, since the design approach could just be totally flawed). Does anyone know a way to solve what I am trying to do? I would really appreciate if you could just point me to a possible way to address the issues that I am having with my current implementation. BTW, I am definitely open to completely different ideas for solving this problem too.
You cannot overload functions based on return value [1]. This is precisely why the standard IO library uses the construct:
std::cin >> a >> b;
which may not be your piece of cake -- many people don't like it, and it is truly not without its problems -- but it does a nice job of providing a target type to the parser. It also has the advantage over a static parse<X>(const std::string&) prototype that it allows for chaining and streaming, as above. Sometimes that's not needed, but in many parsing contexts it is essential, and the use of operator>> is actually a pretty cool syntax. [2]
The standard library doesn't do what would be far and away the coolest thing, which is to skip string constants scanf style and allow interleaved reading.
vector<int> integers;
std::cin >> "[" >> interleave(integers, ",") >> "]";
However, that could be defined. (Possibly it would be better to use an explicit wrapper around the string literals, but actually I prefer it like that; but if you were passing a variable you'd want to use a wrapper).
[1] With the new auto declaration, the reason for this becomes even clearer.
[2] IO manipulators, on the other hand, are a cruel joke. And error handling is pathetic. But you can't have everything.
Here is an example of libsass parser:
const char* interpolant(const char* src) {
return recursive_scopes< exactly<hash_lbrace>, exactly<rbrace> >(src);
}
// Match a single character literal.
// Regex equivalent: /(?:x)/
template <char chr>
const char* exactly(const char* src) {
return *src == chr ? src + 1 : 0;
}
where rules could be passed into the lex method.

Conversion problems in C++ (string expected)

I have a function that I cannot touch, Is a "log maker", It puts something to print in a file an show it up when I run the file. The problem is that the function only gets const string so if I want to print something I have to convert everything in this data type (I cannot use cout).
itoa & atoi functions are not standard functions so I cannot use it neither. C++ is very "special" with data types and doesn't accept conversions really easy, so this is my question:
How can I convert everytype of data into string for the log purposes?
Probably I should check data type on a function to convert things and returning them into a stringstream (witch I have to convert into a string, of course).
So, any advice on how to do that?
boost::lexical_cast encapsulates the use of ostringstream, so you
could use that. Otherwise, the code isn't that difficult:
template<typename T>
std::string
toString( T const& object )
{
std::ostringstream results;
results << object;
return results.str();
}
(There's no reason to use stringstream here; ostringstream is largely sufficient.
You can use
std::stringstream
or
boost lexical_cast<>
Yes, if you want arbitrary type in string representation stringstream intermediate sounds like a solution.
I assume the functions expects a const std::string & ?
Your approach with std::stringstream is correct. Alternatively you could simply write a toString() method for the class you wish to directly output. However, usually when one wants to output objects to a file, overloads the << operator for that particular type.

Converting/parsing pointer strings and doubles

Assignment:
Read in info from text file (done)
Retrieve only parts of text file using substr method (done)
Store info into instance variables (need help)
Here is the code I am having trouble with:
string* lati;
lati = new string(data.substr(0, data.find_first_of(",")));
double* latDub;
latDub = new double(atof((char *)lati));
this->latitude = *latDub;
I need to store the latitude into the instance variable latitude.
The variable data is the read-in text file.
this->latitude is declared as a double.
I have tested and the variable lati is the correct value, but once I try to convert it into a double the value changes to 0 for some reason. I am specifically supposed to use the atof method when converting!
(char *)lati doesn't do what you think it does. What you're clearly trying to do there is get the char sequence associated with lati, but what you're actually doing is just squeezing a string* into a char* which is all kinds of bad.
There's a member function on std::string that will give you exactly what you want. You should review the documentation for string, and replace (char *)lati with a call to that function.
Why your code compiles, but gives meaningless results has already been explained by adpalumbo. There are two fundamental problems in your code leading to that error, on which I want to expand here.
One is that you use a C-style cast: (T)obj. Basically, that just tells the compiler to shut up, you know what you are doing. That is rarely ever a good idea, because when you do know what you are doing, you can usually do without such casts.
The other one is that you are using objects allocated dynamically on the heap. In C++, objects should be created on the stack, unless you have very good reasons for using dynamic objects. And dynamic objects are usually hidden inside objects on the stack. So your code should read like this:
string lati(data.substr(0, data.find_first_of(",")));
double latDub = /* somehow create double from lati */;
this->latitude = latDub;
Of course, latDub is completely unnecessary, you could just as well write to this->latitude directly.
Now, the common way to convert a string into some other type would be streaming it through a string stream. Removing the unnecessary variables you introduced, your code would then look like this:
std::istringstream iss(data.substr(0, data.find_first_of(",")));
if( !iss >> this->latitude ) throw "Dude, you need error handling here!";
Usually you want to pack that conversion from a string into a utility function which you could reuse throughout your code:
inline double convert3double(const std::string& str)
{
std::istringstream iss(str);
double result;
if( !iss >> result )
throw std::exception("Dang!");
return result;
}
However, since the very same algorithm can be used for all types (for which operator>> is overloaded meaningfully with an input stream as the left operand), just make this a template:
template< typename T >
inline T convert3double(const std::string& str)
{
std::istringstream iss(str);
T result; // presumes default constructor
if( !iss >> result ) // presumes operator>>
throw std::exception("Dang!");
return result;
}