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.
Related
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;
So I have such log class:
#include <iostream>
#include <sstream>
#include <boost/circular_buffer.hpp>
#include <boost/foreach.hpp>
class FlushInternal;
class Log
{
public:
static FlushInternal* endl;
Log(int log_length)
{
i = 0;
messages_buffer = new boost::circular_buffer<std::string>(log_length);
}
template <class T>
Log &operator<<(const T &v)
{
current_message << v;
return *this;
}
Log &operator<<(std::ostream&(*f)(std::ostream&))
{
current_message << *f;
return *this;
}
Log &operator<<(FlushInternal*)
{
++i;
messages_buffer->push_back(current_message.str());
clean_stringstream(current_message);
is_filled();
return *this;
}
boost::circular_buffer<std::string> *messages_buffer;
private:
int i;
std::stringstream current_message;
void is_filled()
{
if (i >= messages_buffer->capacity())
{
i = 0;
BOOST_FOREACH(std::string s, *messages_buffer)
{
std::cout << ++i << ": " << s << " ;" << std::endl;
}
i = 0;
}
}
void clean_stringstream(std::stringstream &message)
{
message.flush();
message.clear();
message.seekp(0);
message.str("");
}
};
FlushInternal* Log::endl = 0;
And I can Use it like this:
#include <log.h>
int main()
{
Log l(2);
l << "message one: " << 1 << Log::endl;
l << "message two:" << " " << 2 << Log::endl;
l << "message " << "three: " << 3 << Log::endl;
l << "message" << " " << "four: " << 4 << Log::endl;
std::cin.get();
}
This would output:
1: message one: 1 ;
2: message two: 2 ;
1: message three: 3 ;
2: message four: 4 ;
As you can see I can have as many << as I want inside each log message. I want to be capable to use one instance of Log class from many threads at the same time. So I would have something like (pseudocode that compiles, runs but traces nothing.):
#include <boost/thread.hpp>
#include <log.h>
Log *l;
void fun_one()
{
*l << "message one: " << 1 << Log::endl;
*l << "message two:" << " " << 2 << Log::endl;
}
void fun_two()
{
*l << "message " << "three: " << 3 << Log::endl;
*l << "message" << " " << "four: " << 4 << Log::endl;
}
int main()
{
l = new Log(2);
boost::thread(fun_one);
boost::thread(fun_two);
std::cin.get();
}
So as you can see I want messages to be inserted into log in multythreaded function. Lo I wonder - how to make my log cclass support this?
The approach linked by trojanfoe is pretty much the canonical one. Basically create some temporary thing for the leftmost << operator, accumulate everything, and output the message in the destructor for the temporary thing.
The only question is the exact mechanics of this accumulator. The example used ostringstream, but I've seen the ofstream for the log file used directly as well (requires locking to ensure the output ends up on one line).
Creating ostringstreams is relatively expensive on some platforms, because they may need to lock and copy some internal locale related things. You could re-implement also the << operator for interesting types, but I'd test the ostringstream approach first.
A useful optimization is determine at the point of the construction of the temporary whether the trace will be emitted (e.g., whether tracing is enabled at that particular level), and not create the guts of the temporary at all in that case - all the insertion operations will be no-ops.
Here's one approach:
http://drdobbs.com/cpp/201804215
It basically creates a new ostringstream object each time you perform logging, which makes it thread safe. I can't say I'm that keen on that, as it seems a little clumsy to me.
You might have a look at the Qt logging classes as they support the << operator, however I'm not sure about thread safety.
Hi below is my function:
string Employee::get_print(void) {
string out_string;
stringstream ss;
ss << e_id << " " << type << endl;
out_string = ss.str();
return out_string;
}
e_id and type are int and they contain values from the class Employee. But when I pass them into the stringstream they just clear the string when I try to out put it. But if I don't have a int in the ss << "Some text" << endl; this output fine. What am I doing wrong =S
//Edit
Ok;
This is the calling code:
tmp = cur->get_print();
Where tmp is a string and cur is an Employee Object.
This code...
stringstream out;
out << "Test " << e_id << " " << e_type;
return out.str();
Retruns "Test " and nothing else. If I take out "Test " << my returned string is ""
I'm using GCC 4.2 on Mac OS/X 10.6.2 if that makes any difference.
I too am unable to reproduce this error. As has been mentioned, don't include the endl, as this actually appends a \n and is supposed to flush the write buffer. For this use, it is completely unnecessary and may actually lead to undesirable results...However, the code in your edit/update works just fine for me.
int main(int argc, char* argv[])
{
int e_id = 5;
int e_type = 123456;
stringstream out;
out << "Test " << e_id << " " << e_type;
cout << out.str();
return 0;
}
Produces:
Test 5 123456
My suggestions would be to double check that e_id and e_type are really just native int.
For further testing, you may want to force a cast on the values to see if it helps as such:
out << "Test " << (int)e_id << " " << (int)e_type;
Since I'm unable to reproduce this error, I'm afraid I'm unable to help any further. But best of luck to you!
Ok I have no idea what is going on with stringstream I've tried using it in other parts of my code and it doesn't work with integers. Therefore, I have reverted to using the sprintf C function:
string Employee::get_print(void) {
char out[50];
sprintf(out, "%d %d", e_id, e_type);
string output = out;
return output;
}
This returns the string which is needed.
I have moved into Netbeans and I don't have this problem. So it is an issue with Xcode.
I think the endl is not needed. You only need to write endl if you want to write a newline on a file on on std::cout.
Since you write endl, your stringstream will contain a string with 2 lines of which the second is empty. This probably confuses you. Remove the endl to get only one line.
I've got exactly the same problem - GCC and stringstream returning nothing.
As I found out, the trick is that you have to put some text data before anything else into the stringstream.
This code...
stringstream ss(stringstream::out);
ss << 3.14159;
cout << "'" << ss.str() << "'" << endl;
gets you this result:
''
But if we put a single "" inside the stringstream first...
stringstream ss(stringstream::out);
ss << "" << 3.14159;
cout << "'" << ss.str() << "'" << endl;
the result is as expected:
'3.14159'
Ok, I must preface this by stating that I know so so little about c++ and am hoping someone can just help me out...
I have the below code:
string GoogleMapControl::CreatePolyLine(RideItem *ride)
{
std::vector<RideFilePoint> intervalPoints;
ostringstream oss;
int cp;
int intervalTime = 30; // 30 seconds
int zone =ride->zoneRange();
if(zone >= 0)
{
cp = 300; // default cp to 300 watts
}
else
{
cp = ride->zones->getCP(zone);
}
foreach(RideFilePoint* rfp, ride->ride()->dataPoints())
{
intervalPoints.push_back(*rfp);
if((intervalPoints.back().secs - intervalPoints.front().secs) > intervalTime)
{
// find the avg power and color code it and create a polyline...
AvgPower avgPower = for_each(intervalPoints.begin(),
intervalPoints.end(),
AvgPower());
// find the color
QColor color = GetColor(cp,avgPower);
// create the polyline
CreateSubPolyLine(intervalPoints,oss,color);
intervalPoints.clear();
intervalPoints.push_back(*rfp);
}
}
return oss.str();
}
void GoogleMapControl::CreateSubPolyLine(const std::vector<RideFilePoint> &points,
std::ostringstream &oss,
QColor color)
{
oss.precision(6);
QString colorstr = color.name();
oss.setf(ios::fixed,ios::floatfield);
oss << "var polyline = new GPolyline([";
BOOST_FOREACH(RideFilePoint rfp, points)
{
if (ceil(rfp.lat) != 180 && ceil(rfp.lon) != 180)
{
oss << "new GLatLng(" << rfp.lat << "," << rfp.lon << ")," << endl;
}
}
oss << "],\"" << colorstr.toStdString() << "\",4);";
oss << "GEvent.addListener(polyline, 'mouseover', function() {" << endl
<< "var tooltip_text = 'Avg watts:" << avgPower <<" <br> Avg Speed: <br> Color: "<< colorstr.toStdString() <<"';" << endl
<< "var ss={'weight':8};" << endl
<< "this.setStrokeStyle(ss);" << endl
<< "this.overlay = new MapTooltip(this,tooltip_text);" << endl
<< "map.addOverlay(this.overlay);" << endl
<< "});" << endl
<< "GEvent.addListener(polyline, 'mouseout', function() {" << endl
<< "map.removeOverlay(this.overlay);" << endl
<< "var ss={'weight':5};" << endl
<< "this.setStrokeStyle(ss);" << endl
<< "});" << endl;
oss << "map.addOverlay (polyline);" << endl;
}
And I'm trying to get the avgPower from this part:
AvgPower avgPower = for_each(intervalPoints.begin(),
intervalPoints.end(),
AvgPower());
the first part to cary over to the second part:
<< "var tooltip_text = 'Avg watts:" << avgPower <<" <br> Avg Speed: <br> Color: "<< colorstr.toStdString() <<"';" << endl
But of course I haven't the slightest clue how to do it... anyone feeling generous today?
Thanks in advance
Well you didn't state the problem with the code other than it doesn't work. I'm suspicious of your use of AvgPower() in the for_each. Also, you have AvgPower as a class. why not a double or something? For this code I would have expected to see something like this:
PowerType addIntervals(const RideFilePoint &p1, const RideFilePoint &p2) {
//Add and return.
}
...
...
PowerType total = accumulate(i.begin(), i.end(), PowerType(0.0), &addIntervals);
avg = total/i.length();
read these docs carefully:
http://www.sgi.com/tech/stl/accumulate.html
It seems like you are asking how to access the local variable avgPower within a different function (sorry if I am misunderstanding). This is less about c++ specifically and more about functional or object oriented design. There are many different ways to do this, but here are the sane ones I can think of, in the order of my preference.
Create avgPower (and color), within CreateSubPolyLine. There doesn't really seem to be any reason they are in CreatePolyLine anyway. Implement a separate call if there are other consumers. The function signature would change to
void GoogleMapControl::CreateSubPolyLine(const std::vector &points,
std::ostringstream &oss)
Include it in the function's paramemters, e.g., change the signature to:
void GoogleMapControl::CreateSubPolyLine(const std::vector &points,
std::ostringstream &oss,
const QColor& color,
const AvgPower& avgPower)
Put it in a member variable of GoogleMapControl. It doesn't seem like this would be a bad design choice in my opinion.
This question already has answers here:
How to concatenate a std::string and an int
(25 answers)
Closed 6 years ago.
int i = 4;
string text = "Player ";
cout << (text + i);
I'd like it to print Player 4.
The above is obviously wrong but it shows what I'm trying to do here. Is there an easy way to do this or do I have to start adding new includes?
With C++11, you can write:
#include <string> // to use std::string, std::to_string() and "+" operator acting on strings
int i = 4;
std::string text = "Player ";
text += std::to_string(i);
Well, if you use cout you can just write the integer directly to it, as in
std::cout << text << i;
The C++ way of converting all kinds of objects to strings is through string streams. If you don't have one handy, just create one.
#include <sstream>
std::ostringstream oss;
oss << text << i;
std::cout << oss.str();
Alternatively, you can just convert the integer and append it to the string.
oss << i;
text += oss.str();
Finally, the Boost libraries provide boost::lexical_cast, which wraps around the stringstream conversion with a syntax like the built-in type casts.
#include <boost/lexical_cast.hpp>
text += boost::lexical_cast<std::string>(i);
This also works the other way around, i.e. to parse strings.
printf("Player %d", i);
(Downvote my answer all you like; I still hate the C++ I/O operators.)
:-P
These work for general strings (in case you do not want to output to file/console, but store for later use or something).
boost.lexical_cast
MyStr += boost::lexical_cast<std::string>(MyInt);
String streams
//sstream.h
std::stringstream Stream;
Stream.str(MyStr);
Stream << MyInt;
MyStr = Stream.str();
// If you're using a stream (for example, cout), rather than std::string
someStream << MyInt;
For the record, you can also use a std::stringstream if you want to create the string before it's actually output.
cout << text << " " << i << endl;
Your example seems to indicate that you would like to display the a string followed by an integer, in which case:
string text = "Player: ";
int i = 4;
cout << text << i << endl;
would work fine.
But, if you're going to be storing the string places or passing it around, and doing this frequently, you may benefit from overloading the addition operator. I demonstrate this below:
#include <sstream>
#include <iostream>
using namespace std;
std::string operator+(std::string const &a, int b) {
std::ostringstream oss;
oss << a << b;
return oss.str();
}
int main() {
int i = 4;
string text = "Player: ";
cout << (text + i) << endl;
}
In fact, you can use templates to make this approach more powerful:
template <class T>
std::string operator+(std::string const &a, const T &b){
std::ostringstream oss;
oss << a << b;
return oss.str();
}
Now, as long as object b has a defined stream output, you can append it to your string (or, at least, a copy thereof).
Another possibility is Boost.Format:
#include <boost/format.hpp>
#include <iostream>
#include <string>
int main() {
int i = 4;
std::string text = "Player";
std::cout << boost::format("%1% %2%\n") % text % i;
}
Here a small working conversion/appending example, with some code I needed before.
#include <string>
#include <sstream>
#include <iostream>
using namespace std;
int main(){
string str;
int i = 321;
std::stringstream ss;
ss << 123;
str = "/dev/video";
cout << str << endl;
cout << str << 456 << endl;
cout << str << i << endl;
str += ss.str();
cout << str << endl;
}
the output will be:
/dev/video
/dev/video456
/dev/video321
/dev/video123
Note that in the last two lines you save the modified string before it's actually printed out, and you could use it later if needed.
For the record, you could also use Qt's QString class:
#include <QtCore/QString>
int i = 4;
QString qs = QString("Player %1").arg(i);
std::cout << qs.toLocal8bit().constData(); // prints "Player 4"
cout << text << i;
One method here is directly printing the output if its required in your problem.
cout << text << i;
Else, one of the safest method is to use
sprintf(count, "%d", i);
And then copy it to your "text" string .
for(k = 0; *(count + k); k++)
{
text += count[k];
}
Thus, you have your required output string
For more info on sprintf, follow:
http://www.cplusplus.com/reference/cstdio/sprintf
cout << text << i;
The << operator for ostream returns a reference to the ostream, so you can just keep chaining the << operations. That is, the above is basically the same as:
cout << text;
cout << i;
cout << "Player" << i ;
cout << text << " " << i << endl;
The easiest way I could figure this out is the following..
It will work as a single string and string array.
I am considering a string array, as it is complicated (little bit same will be followed with string).
I create a array of names and append some integer and char with it to show how easy it is to append some int and chars to string, hope it helps.
length is just to measure the size of array. If you are familiar with programming then size_t is a unsigned int
#include<iostream>
#include<string>
using namespace std;
int main() {
string names[] = { "amz","Waq","Mon","Sam","Has","Shak","GBy" }; //simple array
int length = sizeof(names) / sizeof(names[0]); //give you size of array
int id;
string append[7]; //as length is 7 just for sake of storing and printing output
for (size_t i = 0; i < length; i++) {
id = rand() % 20000 + 2;
append[i] = names[i] + to_string(id);
}
for (size_t i = 0; i < length; i++) {
cout << append[i] << endl;
}
}
There are a few options, and which one you want depends on the context.
The simplest way is
std::cout << text << i;
or if you want this on a single line
std::cout << text << i << endl;
If you are writing a single threaded program and if you aren't calling this code a lot (where "a lot" is thousands of times per second) then you are done.
If you are writing a multi threaded program and more than one thread is writing to cout, then this simple code can get you into trouble. Let's assume that the library that came with your compiler made cout thread safe enough than any single call to it won't be interrupted. Now let's say that one thread is using this code to write "Player 1" and another is writing "Player 2". If you are lucky you will get the following:
Player 1
Player 2
If you are unlucky you might get something like the following
Player Player 2
1
The problem is that std::cout << text << i << endl; turns into 3 function calls. The code is equivalent to the following:
std::cout << text;
std::cout << i;
std::cout << endl;
If instead you used the C-style printf, and again your compiler provided a runtime library with reasonable thread safety (each function call is atomic) then the following code would work better:
printf("Player %d\n", i);
Being able to do something in a single function call lets the io library provide synchronization under the covers, and now your whole line of text will be atomically written.
For simple programs, std::cout is great. Throw in multithreading or other complications and the less stylish printf starts to look more attractive.
You also try concatenate player's number with std::string::push_back :
Example with your code:
int i = 4;
string text = "Player ";
text.push_back(i + '0');
cout << text;
You will see in console:
Player 4
You can use the following
int i = 4;
string text = "Player ";
text+=(i+'0');
cout << (text);
If using Windows/MFC, and need the string for more than immediate output try:
int i = 4;
CString strOutput;
strOutput.Format("Player %d", i);