fatal error on std::transform c++ [duplicate] - c++

This question already has answers here:
Why fill_n() does not work with vector.reserve()?
(3 answers)
Closed 5 years ago.
I'm trying to transform a vector of foo instances to a string but I'm having fatal error on std::transform.
Say data has the following value:
[0]
[name] = John
[size] = 3423
[1]
[name] = Joseph
[size] = 3413
Code:
struct foo {
foo(std::string n, size_t s)
: name(std::move(n)),
size(s)
{
}
std::string name;
size_t size;
};
std::string server = "1";
std::vector<std::string> output;
output.reserve(static_cast<unsigned_long>(std::distance(std::begin(data), std::end(data))));
std::transform(std::begin(data),
std::end(data),
std::begin(output),
[&, this](foo const& item){
std::ostringstream result;
data << server << ","
<< item.name << ","
<< item.size << ";";
return result.str();
});
While debugging it stops at the line
*__result = __unary_op(*_first) of tranform implementation in stl_algo.h then goes to FatalConditionHandler of catch test framework. I'm new to both catch testing and std::transform. Can someone explain what might cause the problem and how to solve it? Thanks a lot!

You've reserved space in output, but you've left its size at zero.
You then proceed to write through its begin iterator, just as if it had space to hold data.
Then everything goes "boom".
Instead of writing through std:begin(output), consider using std::back_inserter(output) as the destination iterator.
You also have one other problem: inside your lambda, you have:
std::ostringstream result;
data << server << ","
<< item.name << ","
<< item.size << ";";
return result.str();
This looks like a fairly obvious mistake--you undoubtedly intended:
std::ostringstream result;
result << server << ","
<< item.name << ","
<< item.size << ";";
return result.str();
Personally, I'd probably structure the code somewhat differently. I'd add something like:
struct foo {
std::string name;
size_t size;
// new addition:
friend std::ostream &operator<<(std::ostream &os, foo const &f) {
return os << f.name << ',' << f.size;
}
};
...then the lambda in your transform becomes rather simpler:
std::ostringstream result;
result << server << "," item;
return result.str();
It might, however, be worth considering doing this without the stringstream itermediaries at all. In this case, you really just need string concatenation, and they impose quite a bit of overhead to do that.
struct foo {
// ...
std::string to_string() {
return name + "," + size;
}
};
Then the lambda body becomes:
return server + "," + item.to_string();
Shorter, simpler, and almost certainly faster.

Related

property_tree get array value as String

I want to parse a json file/string with boosts property_tree, but instead of having sub-trees parsed into an array I would like it to stay as a string for use in another existing function which only deals with json-Strings.
I hope the following example is sufficient:
example.json
{
"type": "myType",
"colors": {
"color0":"red",
"color1":"green",
"color2":"blue"
}
}
main.cpp
std::stringstream ss("example.json");
ptree pt;
read_json(ss, pt);
std::string sType = pt.get("type", "");
std::string sColors = pt.get<std::string>("colors");
std::cout << "sType: " << sType << std::endl; // sType: myType
std::cout << "sColors: " << sColors << std::endl; // sColors: {"color0":"red", "color1":"green", "color2":"blue"}
I've tried several functions, for example pt.get_child("colors") would just return another ptree and pt.get_value<std::string>("colors") does return an empty string ("").
The desired output would look like this:
sColors: {"color0":"red", "color1":"green", "color2":"blue"}
or
sColors: {\"color0\":\"red\", \"color1\":\"green\", \"color2\":\"blue\"}
Is there a way to recive the desired output for sColors?
I found a possible solution faster than anticipated, the following code will provide a satisfactory answer:
std::stringstream os;
write_json(os, pt.get_child("colors"), false);
std::string sColors = os.str();
std::cout << "sColors: " << sColors << std::endl;
If there is a more elegant solution feel free to post it as well!

Unable to concat strings in C++?

I have a method to log with the following definition:
void log(std::string s) {
std::string tag = "main";
std::cout << tag << " :" << s << std::endl;
}
I'm trying to call this method like this:
log("direction" << std::to_string(direction) << ", count: " << std::to_string(count));
direction and count are integers.
I'm getting this following error with << underlined in red:
no operator << matches these operands.
operand types are const char [10] << std::string
I have #include<string> in my header to make sure my strings are working as they should.
I tried std::string("direction") and still the issue was same.
Beginner in C++. Help would be appreciated.
operator<< isn't used for arbitrary string concatenation - it is called an "output stream operator", and it is only used in the context of std::ostream.
When you say...
std::cout << tag << " :" << s << std::endl;
...you're actually writing code roughly equivalent to:
std::cout.operator<<(tag).operator<<(" :").operator<<(s).operator<<(std::endl);
As you can see operator<< knows how to work with std::cout and std::string, but not between strings.
In order to concatenate std::string instances, you can simply use operator+:
log("direction" + std::to_string(direction) + ", count: " + std::to_string(count));
Please note that this concatenation technique is not the most efficient: you might want to look into std::stringstream or simply use std::string::reserve to avoid unnecessary memory allocations.
Substitute the << with the + operator as you are manipulating the string, not the stream:
log("direction" + std::to_string(direction) + ", count: " + std::to_string(count));
If you're determined to use the operator<< notation you need an object that understands it.
Here's such an object (I make no claims that this is a good idea):
#include <string>
#include <sstream>
#include <iostream>
void log(std::string s) {
std::string tag = "main";
std::cout << tag << " :" << s << std::endl;
}
struct string_accumulator
{
std::ostringstream ss;
template<class T>
friend string_accumulator& operator<<(string_accumulator& sa, T const& value)
{
sa.ss << value;
return sa;
}
template<class T>
friend string_accumulator& operator<<(string_accumulator&& sa, T const& value)
{
return operator<<(sa, value);
}
operator std::string () { return ss.str(); }
};
inline auto collect() -> string_accumulator
{
return string_accumulator();
}
int main()
{
int direction = 1;
int count = 1;
log(collect() << "direction" << std::to_string(direction) << ", count: " << std::to_string(count));
}
The prototype of your function is void log(std::string s);. It awaits for an std::string. So you need to pass a string to it, not a stream!
So, change this:
log("direction" << std::to_string(direction) << ", count: " << std::to_string(count));
to this:
log("direction" + std::to_string(direction) + ", count: " + std::to_string(count));
where I only changed the << operator to + operator. It will now concatenate everything inside the parentheses to a single std::string.
Your attempt implies that you wanted to pass std::ostream as the parameter. Maybe you want to read C++ Passing ostream as parameter. However, if I were you, I would just overload <<.
why don't you use:
// just include thisusing namespace std;

How do I stream into a string without creating a named stringstream?

I often end up writing code like this:
SomeStreamableType x;
std::stringstream ss;
ss << "Value is: " << x;
log(ss.str());
The extra line needed to generate the stringstream feels superfulous. I can do this, but it's equally cumbersom:
SomeStreamableType x;
const std::string str = "Value is: " + boost::lexical_cast<std::string>(x);
log(str);
I want to be able to do this:
SomeStreamableType x;
log(std::stringstream() << "Value is: " << x);
Have others encountered this issue and come up with a workaround? I don't want to create any helper functions or classes.
Your code will work without modifications, as long as log accepts an ostream& reference:
void log(ostream& o) {
stringstream* s = dynamic_cast<stringstream*>(&o);
if (s) {
cout << s->str() << endl;
}
}
int main() {
int x = 5, y = 6;
log(stringstream() << "x=" << x << ", y=" << y);
return 0;
}
Demo.
To solve this problem I have often simply done something like this:
#define LOG(m) do{std::ostringstream oss;oss<<m;std::cout<<oss.str()<<'\n';}while(0)
// ...
LOG("some text: " << value1 << ' ' << value2); // no need for '\n'
Now I tend to use a more sophisticated class based solution that has an even nicer interface and doesn't use a horrible macro.

No match for 'operator<<' in std::cout [duplicate]

This question already has answers here:
no match for ‘operator<<’ in ‘std::operator
(6 answers)
Closed 5 years ago.
I am developing gsoap web service where I am retrieving vectors of objects in return of a query. I have two ways to do it: first by simple loop and by iterator. None of them working.
The error is:
error: no match for 'operator<<' in 'std::cout
mPer.MultiplePersons::info.std::vector<_Tp, _Alloc>::at<PersonInfo, std::allocator<PersonInfo> >(((std::vector<PersonInfo>::size_type)i))'
MultiplePersons mPer; // Multiple Person is a class, containing vector<PersonInfo> info
std::vector<PersonInfo>info; // PersonInfo is class having attributes Name, sex, etc.
std::vector<PersonInfo>::iterator it;
cout << "First Name: \t";
cin >> firstname;
if (p.idenGetFirstName(firstname, &mPer) == SOAP_OK) {
// for (int i = 0; i < mPer.info.size(); i++) {
// cout << mPer.info.at(i); //Error
//}
for (it = info.begin(); it != info.end(); ++it) {
cout << *it; // Error
}
} else p.soap_stream_fault(std::cerr);
}
It's obvious that operator overloading operator<< in cout is the problem. I have looked at several problems related to this, but no one helped me out. If someone can provide a concrete example on how to solve it, it would be very appreciated. (Please do not talk in general about it, I am new to C++ and I have spent three days on it searching for solution.)
You need to provide an output stream operator for PersonInfo. Something like this:
struct PersonInfo
{
int age;
std::string name;
};
#include <iostream>
std::ostream& operator<<(std::ostream& o, const PersonInfo& p)
{
return o << p.name << " " << p.age;
}
This operator allows expressions of the type A << B, where A is an std::ostream instance (of which std::cout is one) and B is a PersonInfo instance.
This allows you do do something like this:
#include <iostream>
#include <fstream>
int main()
{
PersonInfo p = ....;
std::cout << p << std::endl; // prints name and age to stdout
// std::ofstream is also an std::ostream,
// so we can write PersonInfos to a file
std::ofstream person_file("persons.txt");
person_file << p << std::endl;
}
which in turn allows you to print the de-referenced iterator.
The result of *it is an L-value of type PersonInfo. The compiler is complaining that there is no operator<< which takes a right-hand side argument of type PersonInfo.
For the code to work, you need to provide such an operator, for example like this:
std::ostream& operator<< (std::ostream &str, const PersonInfo &p)
{
str << "Name: " << p.name << "\nAge: " << p.age << '\n';
return str;
}
The exact implementation of the operator depends on your needs for representing the class in output, of course.
What it's telling you is that there isn't a known wway to cout (console output) the contents of *it.
it is an iterator - think of this like a pointer in a list
the list is info so *it is current item in the info, which is a list of PersonInfo items.
So cout << *it; says output to the console the PersonInfo that it is currently referencing.
But the error message is telling you that the compiler doens't know how PersonInfo should be rendered to the console.
What you need to do is create an operator called << that takes an object that cout is (ostream) and a PersonInfo object and then writes the various bits of the PersonInfo to cout.

C++ writing multiple strings from a file

Quick question. I'm doing my portfolio C++ question for a uni assignment. It is standard deviation. My question is to do with reading multiple strings from a file, see text here;
Design and write a c++ program that reads a set of scores from the file scored.dat, and outputs their mean and standard deviation to cout.
I'm not going to bother with the actual equation, I have that part nearly sorted. My query is based directly on outputting the text read from the file into strings. For example, if the document had these three scores:
10
15
11
Instead of outputting the text as it is, it would put them into three strings;
Score_One (Which would be 10)
Score_Two (Which would be 15)
Score_Three (Which would be 11)
I hope I am making sense here guys. Thanks.
you need to do something like this:
int raw_score_one = 11; //you have already set this but for the sake of clarity
std::stringstream output;
output << raw_score_one;
std::string Score_One = output.str();
for each score...
Here is a solution which was just fun to write and which hardly a solution I would expect to show up. It may have some entertainment and/or educational value as well. The basic idea is that values a written as
std::cout << 10 << 15 << 11 << reset << '\n';
std::cout << 1 << 2 << 3 << reset << '\n';
To achieve this, a bit of machinery is needed but it isn't that bad, really. The code is blow:
#include <locale>
#include <iostream>
#include <algorithm>
static int index(std::ios_base::xalloc());
static std::string const names[] = { "One", "Two", "Three", "Four", "Five" };
static std::string const score("Score_");
static std::string const other(" (Which would be ");
std::ostream& reset(std::ostream& out)
{
out.iword(index) = 0;
return out;
}
struct num_put
: std::num_put<char>
{
iter_type do_put(iter_type to, std::ios_base& fmt, char_type fill,
long v) const {
to = std::copy(score.begin(), score.end(), to);
if (fmt.iword(index) < 5) {
to = std::copy(names[fmt.iword(index)].begin(),
names[fmt.iword(index)].end(), to);
++fmt.iword(index);
}
else {
throw std::runtime_error("index out of range!");
}
to = std::copy(other.begin(), other.end(), to);
to = this->std::num_put<char>::do_put(to, fmt, fill, v);
*to++ = ')';
*to++ = ' ';
return to;
}
};
int main()
{
std::cout.imbue(std::locale(std::locale(), new num_put));
std::cout << 10 << 15 << 11 << reset << '\n';
std::cout << 1 << 2 << 3 << reset << '\n';
}