Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
Problem:
From overloaded operator<<, cout will only print first bit:``"Hello guys, ", while the stream is multiple shifts << "Hello guys, " << "I can't get here!" << str << "\n"`.
My question is, why I only get the first bit of stream?
Code:
#include <iostream>
#include <sstream>
#include <string>
class Debug {
private:
std::stringstream stream;
public:
std::string str() const{
return stream.str();
}
std::stringstream& operator<<(std::string &s) {
stream << s;
std::cout << s;
return stream;
}
std::stringstream& operator<<(const char s[]) {
stream << s;
std::cout << s;
return stream;
}
};
std::ostream &operator<<(std::ostream &output, const Debug &d) {
output << d.str();
return output;
}
int main() {
Debug debug;
std::string str("Bad input");
debug << "Hello guys, " << "I can't get here!" << str << "\n";
std::cout <<"\n\n"<< debug;
std::cin.get();
return 0;
}
My question is, why I only get the first bit of stream?
as it was mentioned in the comments, any further calls after the 1st one of the Debug::operator<<() overload, will go to the overloaded operator of std::stringstream because you return a reference to that one.
What you probably want is a class that wraps a std::ostream interface like follows:
class Debug {
std::ostream& os_;
public:
Debug(std::ostream& os) : os_(os) {}
template<typename T>
Debug& operator<<(T val) {
// Intercept whatever you want to intercept here ...
os_ << val;
return *this;
}
};
This will ensure that the Debug::operator<<() overload is called repeatedly when the statement
debug << "Hello guys, " << "I can't get here!" << str << "\n";
is going to be executed.
int main() {
Debug debug(std::cout);
std::string str("Bad input");
debug << "Hello guys, " << "I can't get here!" << str << "\n";
return 0;
}
Outputs:
Hello guys, I can't get here!Bad input
See the Live Demo.
To collect the stuff at an inner stream, and just output the contents at a certain point, you can do it as follows:
#include <iostream>
#include <string>
#include <sstream>
class Debug {
std::ostringstream os_;
public:
template<typename T>
Debug& operator<<(T val) {
os_ << val;
return *this;
}
// Overload the operator<< to output the buffered stuff
friend std::ostream& operator<<(std::ostream& os, const Debug& debug) {
os << debug.os_.str();
return os;
}
};
int main() {
Debug debug;
std::string str("Bad input");
debug << "Hello guys, " << "I can't get here!" << str << "\n";
std::cout << debug;
return 0;
}
Another Live Demo.
Related
This question already has an answer here:
C++ std::stringstream operator<< overloading
(1 answer)
Closed 3 years ago.
Here's my toy program. It fails to compile with error message " no operator << matches these operands". Any help will be appreciated.
struct foo {
std::string name;
};
std::ostringstream& operator<<(std::ostringstream& os, const foo& info)
{
os << info.name;
return os;
}
void insert(const foo& info)
{
std::ostringstream os;
os << "Inserted here " << info; // don't work here
}
int main()
{
foo f1;
f1.name = "Hello";
insert(f1);
}
The reason
os << "Inserted here " << info;
does not work is
os << "Inserted here "
returns a std::ostream&, not a std::ostringstream&.
Options:
Change your function to be use std::ostream instead of std::ostringstream.
std::ostream& operator<<(std::ostream& os, const foo& info) { ... }
Change how you use it. Use
os << "Inserted here ";
os << info;
I strongly recommend using the first option.
I'm trying to print an object Order (actually a vector of Orders). Order has some data members, including a vector with other objects, Purchase.
I can print the vector<Purchase> to cout on its own, and I can print vector<Objects> if I ignore the vector<Purchase> member. But the tricky part is to print vector<Objects> with vector<Purchase> included.
Here is my code:
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <algorithm>
#include <sstream>
using namespace std;
struct Purchase {
string name;
double unit_price;
int count;
};
struct Order {
string name;
string adress;
double data;
vector<Purchase> vp;
};
template<typename Iter> //this is my general print-vector function
ostream& print(Iter it1, Iter it2, ostream& os, string s) {
while (it1 != it2) {
os << *it1 << s;
++it1;
}
return os << "\n";
}
ostream& operator<<(ostream& os, Purchase p) {
return os << "(" << p.name << ", " << p.unit_price << ", " << p.count << ")";
}
ostream& operator<<(ostream& os, Order o) {
vector<Purchase> vpo = o.vp;
ostringstream oss;
oss << print(vpo.begin(), vpo.end(), oss, ", "); //This is what I would like to do, but the compiler doesn't like this conversion (from ostream& to ostringstream)
os << o.name << "\n" << o.adress << "\n" << o.data << "\n"
<< oss << "\n";
return os;
}
int main() {
ifstream infile("infile.txt");
vector<Order> vo;
read_order(infile, vo); //a function that reads a txt-file into my vector vo
print(vo.begin(), vo.end(), cout, "");
return 0;
}
As you can see, I had the idea to use ostringstreams as a temporary variable, that I would store the vector<Purchase> before I pass it on to the ostream& os. But this is a no go. What would be a good solution to this problem?
I am fairly new to C++ and are just learning the different uses of streams, so please bear with me if this is a stupid question.
Looks like you have two minor typos.
First, remove the indicated portion:
oss << print(vpo.begin(), vpo.end(), oss, ", ")
// ↑↑↑↑↑↑↑
Then, later in that same function, you cannot stream a stringstream, but you can stream the string serving as its underlying buffer, so use std::stringstream::str():
os << o.name << "\n" << o.adress << "\n" << o.data << "\n"
<< oss.str() << "\n";
// ↑↑↑↑↑↑
With those fixes in place, and the missing read_order function abstracted away, your program compiles.
The easiest way is to write an overload of operator<< that takes a const reference to a std::vector<Purchase> and then just stream the vector into the ostream:
std::ostream& operator<<(std::ostream& os, const std::vector<Purchase>& v);
here is my function
ostream margain(std::string firstWord)
{
ostream x;
x << std::setw(20) << firstWord;
return x;
}
in main I want to use the function as follow
std::cout<< margain("start") << "````````````````````````````````````" << std::endl;
// print things out
//then
std::cout<< margain("End") << "````````````````````````````````````" << std::endl;
I get the output, start or end is not shown, and the return value is
0````````````````````````````````````
how can I fix it? and why?
Edit:
I know that the function is what causing that, because if I add this
cout << std::setw(20) << firstWord;
in the function, It prints right,
I fixed it, not the best way, but as
calling the function as
margain(std::cout, "End") <<
"~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~" << endl;
the function looks like
ostream& margain(ostream& stream, std::string firstWord)
{
stream << std::left << std::setw(10) << firstWord;
return stream;
}
anyone know better way?
You are printing the value of the ostream, not value of firstword. The ostream x in this case is an unopened stream, so it doesn't "do" anything. Because the compiler allows to conversion to either bool (C++11) or void * (before C++11), the "value" from that conversion is printed. Note that any operations on x will not affect cout.
The easiest solution, I would think is to actually add std::setw(20) to your output line:
std::cout<< std::setw(20 << "End" << "````````````````````````````````````" << std::endl;
The other choice would be to pass the std::cout to margain, and return the std::string, something like this:
std::string margain(ostream& x, const std::string& firstWord)
{
x << std::setw(20);
return firstWord;
}
then you could do:
std::cout<< margain(cout, "start") << "````````````````````````````````````" << std::endl;
But it's not exactly flexible or "neat".
The third option is of course to have a MarginString class:
class MarignString
{
private:
int margin;
std::string str;
public:
MarginString(int margin, std::string str) margin(margin), str(str) {}
operator std::string() { return str; }
friend std::ostream& operator(std::ostream& os, const MarginString& ms);
};
std::ostream& operator(std::ostream& os, const MarginString& ms)
{
os << std::setw(ms.margin) << ms.str;
return os;
}
...
std::cout<< MarginString(20, "start") << "````````````````````````````````````" << std::endl;
Note that this last way is probably not that great either... ;)
struct margin
{
margin(std::string word) : word(word) { }
friend std::ostream& operator <<(std::ostream& os, margin const& m)
{
return os << std::setw(20) << m.word;
}
private:
std::string word;
};
I'm searching the best way to add a custom, initial message to all the messages that std::cout (or std::cerr) prints to console/file output.
For example, if I setup that this custom prompt message will be the string "[Log]", then a classic
std::cerr << "This is a log message" << std::endl;
will be printed in this way:
> [Log] This is a log message
Clearly I can obtain this behavior using
std::string PROMPT_MSG = "[Log]";
std::cerr << PROMPT_MSG << "This is a log message" << std::endl;
but I'd like a less invasive way.
Thanks in advance
You could write your own class:
#include <iostream>
#include <string>
class MyLogger
{
std::ostream & out;
std::string const msg;
public:
MyLogger(std::ostream & o, std::string s)
: out(o)
, msg(std::move(s))
{ }
template <typename T>
std::ostream & operator<<(T const & x)
{
return out << msg << x;
}
};
MyLogger MyErr(std::cerr, "[LOG] ");
Usage:
MyErr << "Hello" << std::endl;
As Joachim Pileborg suggested you can use a logging framework. YOu can use an existing one or start with your own that will contain just one class:
class MyLogger{}
template <typename T>
MyLogger& operator << (MyLogger& logger, const T& logStuff)
{
std::cerr << PROMPT_MSG << logStuff << std::endl;
return logger;
}
then define a global variable of class MyLogger:
MyLogger mylogger;
then when you want to write a log record, write:
mylogger << "This is a log message";
overloaded operator << of class MyLogger will do what you want;
I had the same problem in a recent project. I solved it with this little class:
class DebugOut
{
public:
static const int COLUMN_WIDTH = 15;
DebugOut(const std::wstring &type)
{
std::wcout << type;
for(int i=type.length();i<COLUMN_WIDTH;i++)
std::wcout << " ";
std::wcout << ": ";
}
~DebugOut()
{
std::wcout << std::endl;
}
template <typename T>
friend DebugOut& operator<<(DebugOut& out,T i)
{
std::wcout << i;
return out;
}
};
Sample usage: DebugOut(L"Log") << "Something";
I guess you could just define a function log and a function error, and then just call them when you want to print a log or error method. That way you don't have to add the PROMPT_MSG every time.
I need a class that redirects one ostream to another ostream during the lifetime of its object. After some tinkering I came up with this:
#include <iostream>
#include <fstream>
class ScopedRedirect
{
public:
ScopedRedirect(std::ostream & inOriginal, std::ostream & inRedirect) :
mOriginal(inOriginal),
mRedirect(inRedirect)
{
mOriginal.rdbuf(mRedirect.rdbuf(mOriginal.rdbuf()));
}
~ScopedRedirect()
{
mOriginal.rdbuf(mRedirect.rdbuf(mOriginal.rdbuf()));
}
private:
ScopedRedirect(const ScopedRedirect&);
ScopedRedirect& operator=(const ScopedRedirect&);
std::ostream & mOriginal;
std::ostream & mRedirect;
};
int main()
{
std::cout << "Before redirect." << std::endl;
std::ofstream filestream("redirected.txt");
{
ScopedRedirect redirect(std::cout, filestream);
std::cout << "During redirect." << std::endl;
}
std::cout << "After redirect." << std::endl;
return 0;
}
It seems to work fine. However, it's weird that the following line is repeated in both the constructor and destructor:
mOriginal.rdbuf(mRedirect.rdbuf(mOriginal.rdbuf()));
I think it's correct, but I would like to verify with the SO community. Can you find any errors or dangers in this code?
Edit
Make non-copyable.
The reason those lines are the same is because what you're doing is swapping the buffers. (That is, you "redirect" by swapping the original buffer with the redirect buffer; restoration is the swap back.)
While this might give you the intended effect with respect to the output stream, it's not correct because the redirect stream now outputs somewhere else. To redirect means to take one stream and make it output somewhere else; note this doesn't effect that 'somewhere else'.
Your class is not a redirect; as is, it should really be named ScopedStreamSwap. For example, try this instead:
#include <iostream>
#include <fstream>
class ScopedRedirect
{
public:
ScopedRedirect(std::ostream & inOriginal, std::ostream & inRedirect) :
mOriginal(inOriginal),
mRedirect(inRedirect)
{
mOriginal.rdbuf(mRedirect.rdbuf(mOriginal.rdbuf()));
}
~ScopedRedirect()
{
mOriginal.rdbuf(mRedirect.rdbuf(mOriginal.rdbuf()));
}
private:
ScopedRedirect(const ScopedRedirect&);
ScopedRedirect& operator=(const ScopedRedirect&);
std::ostream & mOriginal;
std::ostream & mRedirect;
};
int main()
{
std::cout << "Before redirect." << std::endl;
std::ofstream filestream("redirected.txt");
{
ScopedRedirect redirect(std::cout, filestream);
std::cout << "During redirect." << std::endl;
// oops:
filestream << "also to the file, right?...nope" << std::endl;
filestream << "ah, why am i on the screen?!" << std::endl;
}
std::cout << "After redirect." << std::endl;
// in main, return 0 is implicit, if there is no return statement;
// helpful to keep in mind in snippets and short things
}
What you want is this:
#include <iostream>
#include <fstream>
class ScopedRedirect
{
public:
ScopedRedirect(std::ostream & inOriginal, std::ostream & inRedirect) :
mOriginal(inOriginal),
mOldBuffer(inOriginal.rdbuf(inRedirect.rdbuf()))
{ }
~ScopedRedirect()
{
mOriginal.rdbuf(mOldBuffer);
}
private:
ScopedRedirect(const ScopedRedirect&);
ScopedRedirect& operator=(const ScopedRedirect&);
std::ostream & mOriginal;
std::streambuf * mOldBuffer;
};
int main()
{
std::cout << "Before redirect." << std::endl;
std::ofstream filestream("redirected.txt");
{
ScopedRedirect redirect(std::cout, filestream);
std::cout << "During redirect." << std::endl;
// yay:
filestream << "also to the file, right?...yes" << std::endl;
filestream << "i am not on the screen" << std::endl;
}
std::cout << "After redirect." << std::endl;
return 0;
}