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.
Related
I am trying to write my program so that it can process either StdIn or a file specified on the command line.
I'm doing this by trying to initialize a reference to an istream to either refer to cin or an ifstream, using a conditional.
(similar techniques are described here and here)
But when I try with ifstream, I seem to get an error that the basic_istream move-constructor is declared protected.
istream& refToCIN ( cin ); // This is OK
const istream& refToFile = ifstream(args[1]); // This is OK
const istream& inStream ( FileIsProvided()? ifstream(args[1]) : cin );
// This causes error:
// std::basic_istream<char,std::char_traits<char>>::basic_istream' :
// cannot access protected member declared in class std::basic_istream<char,std::char_traits<char>>
ProcessStream(inStream); // This could either be a file or cin
Can this be reasonably done this way? Is there a good alternative I'm overlooking?
The problem with your code is following:
Your left-hand side of the ternary operator is a temporary (rvalue). However, your right hand-side is an lvalue (cin is an lvalue). As a result, compiler is trying to create a temporary out of cin, and fails because of copy constructor being not available.
As for the sultions - you can simply replace rdbuf() of cin with rdbuf() of your file, and use cin everywhere.
Here's the ultimate solution OP came up with:
ifstream file;
std::streambuf* old_cin_buf = cin.rdbuf(); // Store the old value
if (FileIsProvided())
{
file.open(args[1]);
old_cin_buf = cin.rdbuf(file.rdbuf()); // Replace the ReadBuffer on cin.
// Store the previous value as well.
}
// Use cin for all operations now. It will either use the File or StdIn as appropriate.
...
// Restore the original value, in case it was changed by using a file.
cin.rdbuf(old_cin_buf); // This is better be done before file object here goes out of scope
This smells like an XY problem because you don't need a ternary conditional or reference here.
As a matter of convention, many programs use - to denote stdin rather than omitting a filename. That's one possible avenue. On a similar line of thought, I would use Boost.ProgramOptions or getopt instead of manually parsing the command line. This will indirectly solve your XY problem as it'll make the FileIsProvided() function redundant and you'll be getting your options via other methods than using argv[1] directly.
If you have C++11, there's smart pointers or std::reference_wrapper, which allows you to "reseat" references.
As a anti-motivator, consider that classes like ostream_joiner keep a pointer to their internal stream objects, not a reference. Besides, I doubt that you enjoy the thought of having to deal with dangling references from innocuous looking code.
Otherwise...
if (FileIsProvided())
{
std::ifstream ifs(argv[1]);
if (ifs)
{
ProcessStream(ifs);
}
} else {
ProcessStream(std::cin);
}
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;
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.
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;
}
I know the answer to the frequently-asked How do I specify a pointer to an overloaded function?: Either with assignment or with a cast, and every other C++ tutorial uppercases a string like this (give or take static_cast):
transform(in.begin(), in.end(), back_inserter(out), (int(*)(int)) std::toupper);
Or like this:
int (*fp)(int) = std::toupper;
transform(in.begin(), in.end(), back_inserter(out), fp);
Which neatly selects the <cctype> overload of std::toupper.
But this begs the question: How can I select the <locale> overload in a similar manner?
char (*fp2)(char, const std::locale&) = std::toupper;
transform(in.begin(), in.end(), back_inserter(out), fp2);
// error: too few arguments to function
Or, more practically, consider someone trying to use the C++11 std::stoi in an algorithm to convert a vector of strings to a vector of integers: stoi has two overloads (string/wstring), each taking two additional default arguments.
Assuming I don't want to explicitly bind all those defaults, I believe it is impossible to do this without wrapping such call in an auxiliary function or lambda. Is there a boost wrapper or TMP magic to do it for me in completely generic manner? Can a wrapper like call_as<char(char)>(fp2) or, more likely, call_as<int(const std::string&)>(std::stoi) even be written?
It's funny, I was doing something similar. The best way I found to do it was using lambdas as follows, because otherwise, you have to use a typedef to get the right overload and a std::bind to get rid of the locale, or not use the locale. However, this works much more cleanly:
static const std::locale loc;
transform(in.begin(), in.end(), back_inserter(out), [&loc](char c) {
return std::toupper(c, loc);
});
I use the static to save the effort of reallocating each time.
Or you could get a typedef and do:
std::bind((LocaleCompare)std::toupper, std::placeholders::_1, loc); // UGLY!
You could should create a typedef of that functon pointer type, and then cast the function.
typedef char (*LocaleToUpper)(char, const std::locale&) ;
char (*fp2)(char, const std::locale&) = (LocaleToUpper)toupper;