I've got templated code that uses lexical_cast.
Now I want to remove all the lexical_cast calls (because it doesn't work well with /clr).
I need to cast object between std::string and their value.
So, the first direction is easy (T _from, std::string _to) :
std::ostringstream os;
os << _from;
_to = os.str();
But I can't think of a way to do it generically from a string to any type (I need something generic that will work with templates, can't just use specializations for each type and use functions like atoi)
Edit:
Of course I've tried using the ostringstream in the opposite direction. I get this error:
error C2784: 'std::basic_istream<_Elem,_Traits> &std::operator >>(std::basic_istream<_Elem,_Traits> &&,_Elem *)' : could not deduce template argument for 'std::basic_istream<_Elem,_Traits> &&' from 'std::ostringstream'
lexical_cast uses streaming in both directions, << and >>. You could do the same:
std::stringstream sstr;
sstr << _from;
sstr >> _to;
Be sure to include sanity checks though.
Related
I want use the 6th implementation of std::istream::get(...) method.
https://en.cppreference.com/w/cpp/io/basic_istream/get
It takes basic_streambuf& and char_type. I write:
char quote = '\'';
std::stringstream str;
input.get(str, quote); //input is std::istream object
But compiler as if it doesn't see this implementation, it try convert stringstream to char*:
error C2664: 'std::basic_istream<char,std::char_traits> &std::basic_istream<char,std::char_traits>::get(_Elem *,std::streamsize)': cannot convert argument 1 from 'std::stringstream' to '_Elem *'
Couldn't find answer for this. What's wrong? Thanks for help
To get the streambuf associated with a std::stringstream, you need to call rdbuf().
input.get(*str.rdbuf(), quote);
I am trying to use a custom template for IO, and I getting an error :
"error C2678: binary '>>' : no operator found which takes a left-hand operand of
type 'std::ifstream' (or there is no acceptable conversion)"
I have searched and found only suggestions to try including more headers, and have tried including: string, fstream, iostream, istream, vector. I can use an fstream.get(), but I am trying to get space delimited strings. (The format of my file is lines like this: "String1 = String2")
Here is my code:
template <typename OutType>
OutType Read(std::ifstream& in)
{
OutType out;
in >> out;
return out;
}
Any suggestions are very much appreciated! Thanks!
(P.S. Not sure if it will matter for compiler considerations, but I am using Visual Studio 2013.)
The problem is your OutType (which you have not shown us) has no operator>>(istream&, OutType&). You need to define one for every possible OutType.
How you are expecting OutType is known to >> operator? It understands primitives like int,char, etc., but if you want to make OutType available to << you should overload the operator.
I read an answer here showing how to read an entire stream into a std::string with the following one (two) liner:
std::istreambuf_iterator<char> eos;
std::string s(std::istreambuf_iterator<char>(stream), eos);
For doing something similar to read a binary stream into a std::vector, why can't I simply replace char with uint8_t and std::string with std::vector?
auto stream = std::ifstream(path, std::ios::in | std::ios::binary);
auto eos = std::istreambuf_iterator<uint8_t>();
auto buffer = std::vector<uint8_t>(std::istreambuf_iterator<uint8_t>(stream), eos);
The above produces a compiler error (VC2013):
1>d:\non-svn\c++\library\i\file\filereader.cpp(62): error C2440:
'' : cannot convert from
'std::basic_ifstream>' to
'std::istreambuf_iterator>' 1>
with 1> [ 1> _Elem=uint8_t 1> ] 1>
No constructor could take the source type, or constructor overload
resolution was ambiguous
There's just a type mismatch. ifstream is just a typedef:
typedef basic_ifstream<char> ifstream;
So if you want to use a different underlying type, you just have to tell it:
std::basic_ifstream<uint8_t> stream(path, std::ios::in | std::ios::binary);
auto eos = std::istreambuf_iterator<uint8_t>();
auto buffer = std::vector<uint8_t>(std::istreambuf_iterator<uint8_t>(stream), eos);
That works for me.
Or, since Dietmar says this might be a little sketchy, you could do something like:
auto stream = std::ifstream(...);
std::vector<uint8_t> data;
std::for_each(std::istreambuf_iterator<char>(stream),
std::istreambuf_iterator<char>(),
[&data](const char c){
data.push_back(c);
});
ifstream is a stream of char, not uint8_t. You'll need either basic_ifstream<uint8_t> or istreambuf_iterator<char> for the types to match.
The former may not work without some amount of work, since the library is only required to support streams of char and wchar_t; so you probably want istreambuf_iterator<char>.
what the diff in two codes blow:
char buf[2048];
stringstream in(string(buf));
int tmpInt;
while ((in >> tmpInt)) { // wrong, error C2296: '>>' : illegal, left operand has type 'std::stringstream (__cdecl *)(std::string)'
}
and
char buf[2048];
string tmpStr(buf);
stringstream in(tmpStr);
while ((in >> tmpInt)) { // right
}
I think they do same thing: both use string to construct a stringstream object. No matter temp object or a real object, we will call string copy constructor in stringstream(just copy buf content)
IDE: vs2010
So, what the different between this two ways ? or stringstream implement ways .
thanks.
Chris gave away the answer. The code is the equivalent of the following:
stringstream in(string buf);
In C++, people call this the most vexing parse.
The compiler sees it as a function declaration. in is a function which returns a stringstream and accepts a string as an argument. Note that your compiler is telling you this in the error message std::stringstream (__cdecl *)(std::string).
You will need an extra set of parentheses or C++11 uniform initializer syntax to tell the compiler its not a function you are declaring:
stringstream in((string(buf)));
stringstream in{string(buf)};
I'm getting the following error when I compile the following code on Visual Studio 2008 / Windows SDK 7
const UINT a_uint;
UINT result;
throw std::runtime_error( std::string("we did ") + a_uint +
" and got " + result );
Ironically, I ended up with this result:
error C2782: 'std::basic_string<_Elem,_Traits,_Alloc> std::operator +(
const std::basic_string<_Elem,_Traits,_Alloc> &,const _Elem
)' : template parameter '_Elem' is ambiguous
Can someone explain why the error message doesn't explain the real problem (that there is no operator for +ing ints to strings)?
You can reduce that to this
template<typename T>
void f(T, T);
int main() {
f('0', 0); // is T int or char?
}
You try to add an unsigned int to a string. That does not make sense, and the std::string class does not need to take any precautions to add implicit conversions to char here because that would hide such potential programming bugs.
Try to convert the unsigned int to std::string into a decimal/hexadecimal/octal/etc form and then concatenate (you can do that using std::ostringstream or boost::lexical_cast) or fix the bug in other ways you see fit.
Use stringstream (defined in the sstream header) to compose the error message:
std::stringstream ss;
ss << "we did " << a_uint << " and got " << result;
throw std::runtime_error(ss.str());
To a std::string, you can only add other std::strings, ASCIIZ text at an address specified by a const char*, and individual char-acters.
To concatenate other types, you can:
use a stream:
std::ostringstream oss;
oss << "we did " << a_uint << " and got " << result;
throw std::runtime_error(oss.str());
convert it first to a string representation:
throw std::runtime_error(std::string("we did ") +
boost::lexical_cast(a_uint) +
" and got " +
boost::lexical_cast(result));
You might reasonably wonder why C++ doesn't provide operator+(std::string&, X&) for X in { short, int, long, long long, float, double, unsigned short etc. }, or even:
template <typename T>
std::string operator+(std::string& s, T& t)
{
std::ostringstream oss;
oss << t;
return s + oss.str();
}
In many cases it would be convenient. But streams are more powerful as you can tune the padding width and character, floating point precision etc.. Further, char is the 8-bit integer type, so how could the compiler know whether to append a single character with that ASCII value (e.g. 'A' for 65), or an ASCII representation of the numeric ASCII value "65"? (Currently it doesn't handle any ints, so treating it as a single ASCII char isn't confusing). Or should it work for >=16 bit numbers but not 8? That would make it impossible to resize variables to/from 8-bit ints without having to do a complex impact analysis to see which string operations needed to be rewritten. It's also good practice to minimise dependencies: some small but perhaps significant percentage of translation units using string may not currently have to include (and hence spend time parsing) (and hence ostream etc), and in general cyclic dependencies are a "code smell" and frustrate testability (string depends on ostringstream depends on string...).
Next time please post the full error (it should continue "with [ _Elem = ], could be one of [list of ambiguous overloads]").
The problem is that you concatenate UINT with a std::string. This is not a valid operation, you first have to convert the UINT to a std::string (search Google for handy functions). The compiler is trying to do its best and tries to match some of the std::string operators to the UINT. Apparently, it finds some matches but these certainly aren't what you are looking for.