I want to have a function that outputs certain pieces of information to a specific designated source that is inputted to the function. In code, what I mean is:
function output( source ) {
source << "hello" << endl;
}
where source can be a ofstream or cout. So that I can call this function like so:
output(cout) or ofstream otp ("hello"); output(otp)
My question is, how do I characterize source to make this work? It's fair to assume that source will always be a member of the std class
Thanks!
void output(std::ostream &source) {
source << "hello" << std::endl;
}
or even:
template <T>
void output(T &source) {
source << "hello" << std::endl;
}
Write your function as:
std::ostream& output(std::ostream& source )
{
return source << "hello" << endl;
}
Then you can use it as:
output(cout);
//and
ofstream otp ("hello");
output(otp);
//and
output(output(cout));
output(output(output(cout)));
output(output(output(output(cout))));
//and even this:
output(output(output(output(cout)))) << "weird syntax" << "yes it is" ;
By the way, if the output function has many lines, then you can write it as:
std::ostream& output(std::ostream& source )
{
source << "hello" << endl;
source << "world" << endl;
//....
return source;
}
The point is that it should return source. In the earlier version, the function returns source.
You should pass an std::ostream& as argument
function output( source ) {
source << "hello" << endl;
}
If this is a member function, the point of which is to dump data about objects of the class of which it is a member, consider renaming it to operator<<. So, instead of
class Room {
...
// usage myRoom.output(otp)
void output(std::ostream& stream) {
stream << "[" << m_name << ", " << m_age << "]";
}
};
rather, try this:
class Room {
...
// usage opt << myRoom << "\n"
friend std::ostream& operator<<(std::ostream& stream, const Room& room) {
return stream << "[" << room.m_name << ", " << room.m_age << "]";
}
};
That way, you can display the state of your class using a more natural syntax:
std::cout << "My Room: " << myRoom << "\n";
instead of the klunky
std::cout << "My Room: ";
myRoom.output(std::cout);
std::cout << "\n";
IMHO, redirecting output should be done at the user level. Write your C++ like this:
cout << "hello" << endl;
And when executing the application, user can redirect the output to whatever he wants, say a file:
myapp > myfile
Related
Is there a way to create a function which you can use between two << operators in an ostream?
Let's assume the function's name is usd, and might look something like:
std::ostream& usd(std::ostream& os, int value) {
os << "$" << value << " USD";
return os;
}
Then I would like to use it like:
int a = 5;
std::cout << "You have: " << usd(a) << std::endl;
Which would print:
You have: $5 USD
I would prefer a solution without the need for a class.
If you must use a class I would prefer not to mention the class at all when using the usd function. (For example how the std::setw function works)
EDIT:
In my implementation I intend to use the std::hex function, the one described above was just a simplified example but probably shouldn't have.
std::ostream& hex(std::ostream& os, int value) {
os << "Hex: " << std::hex << value;
return os;
}
So I am not sure if a function returning a simple string is sufficient.
To obtain the usage you described:
int a = 5;
std::cout << "You have: " << usd(a) << std::endl;
You'd simply need usd(a) to return something that you have an ostream<< operator for, like a std::string, and no custom ostream<< operator is needed.
For example:
std::string usd(int amount)
{
return "$" + std::to_string(amount) + " USD";
}
You can write other functions to print in other currencies, or to convert between them, etc but if all you want to handle is USD, this would be sufficient.
If you used a class representing money, you could write an ostream<< for that class and you wouldn't need to call a function at all (given that your default ostream<< prints USD)
class Money
{
int amount;
};
std::ostream& usd(std::ostream& os, Money value) {
os << "$" << value.amount << " USD";
return os;
}
int main(int argc, char** argv)
{
Money a{5};
std::cout << "You have: " << a << std::endl; // Prints "You have: $5 USD"
return 0;
}
I don't know how to do this without a class. However, it is easy to do with a class.
struct usd {
int value;
constexpr usd(int val) noexcept : value(val) {}
};
std::ostream& operator<<(std::ostream& os, usd value) {
os << "$" << value.value << " USD";
return os;
}
for hex
struct hex {
int value;
constexpr hex(int val) noexcept : value(val) {}
};
std::ostream& operator<<(std::ostream& os, hex value) {
os << "Hex: " << std::hex << value.value;
return os;
}
usage
int a = 5;
std::cout << "You have: " << usd(a) << std::endl;
std::cout << "You have: " << hex(a) << std::endl;
I hope this time my question is better formulated and formatted.
Here's the code that produces two separate outputs when I think it should not since I use everytime (I think) the overloaded operator<< for an enum type.
#include <iostream>
using namespace std;
enum Etat { Intact = 5 };
class Ship {
public:
Etat etat_;
Ship ( Etat t = Intact) : etat_(t) {}
~ Ship() {}
ostream& description ( ) const { return cout << "Etat: " << etat_ << " --- ";}
//---------------------------------------ˆˆˆˆ----
};
ostream& operator<< ( ostream& s, const Etat& etat_ )
{
switch ( etat_ )
{
case Intact: s << "intact"; break;
default: s << "unknown state";
}
return s;
}
ostream& operator<< ( ostream& s, Ship n ) { return s << "Etat: " << n.etat_ ; }
int main()
{
Etat etat_ = Intact;
cout << endl << endl << "Etat: "
<< etat_ << " \"cout << etat_\"" << endl << endl;
cout << Ship(etat_)
<< " \"cout << Ship(etat_)\"" << endl << endl;
cout << Ship(etat_).description()
<< " \"cout << Ship(etat_).description()\"" << endl << endl;
return 0;
}
This is what I get in the terminal:
Etat: intact "cout << etat_"
Etat: intact "cout << Ship(etat_)"
Etat: 5 --- 1 "cout << Ship(etat_).description()"
Can anyone explain to me why, in the last case, not only it takes the integer value of the enum attribut, but also adds a "1" after the test string " --- "???
The only thing I can think of is because I used an unorthodox return method in description(), ie 'return cout << ..", but it seems to work since the test string appears.
Is there a way to force the use of the operator<< overload in description()?
Thanks
In the description() function you are returning a reference to std::cout and use it in the std::cout call in main function. There is a reason why operator<< takes an ostream reference as it's first argument. You should modify your function like this and all should work:
ostream& description(ostream& os) const {
return os << "Etat: " << etat_ << " --- ";
}
The random "1" printed out there is caused likely due to the ostream in your example trying to print out reference to itself.
I would like to create a class for logging purposes which will behave like std::cout, but will automatically insert additional information to the stream.
a sample usage that I want would be something like (lets not care about object and context type for now, just assume they are std::string) :
Logger l;
l << "Event with object : " << obj << " while in context : " << context;
Then the output would be :
[timestamp] Event with object : [obj_desc] while in context : [this context][eol][flush]
I've been trying with :
template<typename T>
Logger& operator << (const T& msg){
std::cout << timestamp() << msg << std::endl << std::flush;
return *this;
}
but it seems that std::cout cannot resolve the typename T and fails to output a std::string for example while segfaulting.
A possible solution would be to overload this for all types, but this is rather annoying and time consuming.
Is there a better option to decorate std::cout output with more information?
Edit :
I do realize now that endl and flush will be appended to every message which kind of defeat the purpose, but I'm still interested in the general idea. I care more about the monadic syntax to append an arbitrary number of messages than the <<overload
The reason your code does not work is because you have not implemented operator<< for everything you want to pass to it.
This statement:
Logger l;
l << "Event with object : " << obj << " while in context : " << context;
Is basically doing this (assuming operator<< is a member of Logger, which your implementation implies it is):
Logger l;
l.operator<<("Event with object : ").operator<<(obj).operaator<<(" while in context : ").operator<<(context);
So, you need separate overloads of operator<< for string, obj, context, etc. And you need a way to indicate when to flush the complete log message to std::cout.
I would suggest something more like this:
struct LoggerStream
{
std::ostringstream strm;
struct Timestamp
{
};
~LoggerStream()
{
std::string s = strm.str();
if (!s.empty())
std::cout << s << std::flush;
}
LoggerStream& operator<< (const Timestamp &t)
{
strm << "[timestamp] "; // format this however you need
return *this;
}
LoggerStream& operator<< (const object &obj)
{
strm << "[obj_desc]"; // format this however you need
return *this;
}
LoggerStream& operator<< (const context &ctx)
{
strm << "[this context]"; // format this however you need
return *this;
}
LoggerStream& operator<< (std::ostream&(*f)(std::ostream&))
{
if (f == (std::basic_ostream<char>& (*)(std::basic_ostream<char>&)) &std::flush)
{
std::string s = strm.str();
if (!s.empty())
std::cout << s << std::flush;
strm.str("");
strm.clear();
}
else
strm << f;
return *this;
}
template<typename T>
LoggerStream& operator<< (const T& value)
{
strm << value;
return *this;
}
};
class Logger
{
LoggerStream getStream()
{
LoggerStream strm;
strm << Timestamp;
return strm;
}
};
Then you can do things like this:
Logger l;
l.getStream() << "Event with object : " << obj << " while in context : " << context;
...
l.getStream() << "Event with object : " << obj << " while in context : " << context;
...
Logger l;
LoggerStream strm = l.getStream();
strm << "Event with object : " << obj << " while in context : " << context << std::flush;
...
strm << Logger::Timestamp << "Event with object : " << obj << " while in context : " << context << std::flush;
...
Alternatively:
struct Logger
{
std::ostringstream strm;
~Logger()
{
std::string s = strm.str();
if (!s.empty())
std::cout << "[timestamp] " << s << std::flush;
}
Logger& operator<< (const object &obj)
{
strm << "[obj_desc]"; // format this however you need
return *this;
}
Logger& operator<< (const context &ctx)
{
strm << "[this context]"; // format this however you need
return *this;
}
Logger& operator<< (std::ostream&(*f)(std::ostream&))
{
if (f == (std::basic_ostream<char>& (*)(std::basic_ostream<char>&)) &std::flush)
{
std::string s = strm.str();
if (!s.empty())
std::cout << "[timestamp] " << s << std::flush;
strm.str("");
strm.clear();
}
else
strm << f;
return *this;
}
template<typename T>
Logger& operator<< (const T& value)
{
strm << value;
return *this;
}
};
Logger() << "Event with object : " << obj << " while in context : " << context;
...
Logger() << "Event with object : " << obj << " while in context : " << context;
...
Logger l;
l << "Event with object : " << obj << " while in context : " << context << std::flush;
...
l << "Event with object : " << obj << " while in context : " << context << std::flush;
...
You can certainly overload the stream classes if you want, providing operator<< for all the data types you want to support (and that's probably the "correct" way to go) but, if all you're after is a quick way to add logging to a regular stream, there a simpler way:
#include <iostream>
#include <iomanip>
#include <sstream>
#include <ctime>
#include <unistd.h>
#define logcout std::cout << timestamp()
std::string timestamp(void) {
time_t now = time(0);
struct tm *tmx = localtime(&now);
std::ostringstream oss;
oss << '['
<< (tmx->tm_year+1900)
<< '-'
<< std::setfill('0') << std::setw(2) << (tmx->tm_mon+1)
<< '-'
<< std::setfill('0') << std::setw(2) << (tmx->tm_mday)
<< ' '
<< std::setfill('0') << std::setw(2) << (tmx->tm_hour)
<< ':'
<< std::setfill('0') << std::setw(2) << (tmx->tm_min)
<< ':'
<< std::setfill('0') << std::setw(2) << (tmx->tm_sec)
<< "] ";
return oss.str();
}
int main (int argc, char *argv[]) {
logcout << "A slightly\n";
sleep (5);
logcout << "sneaky" << " solution\n";
return 0;
}
which outputs:
[2015-05-26 13:37:04] A slightly
[2015-05-26 13:37:09] sneaky solution
Don't be fooled by the size of the code, I just provided a complete compilable sample for testing. The crux of the matter is the single line:
#define logcout std::cout << timestamp()
where you can then use logcout instead of std::cout, and every occurrence prefixes the stream contents with an arbitrary string (the timestamp in this case, which accounts for the bulk of the code).
It's not what I would call the most pure C++ code but, if your needs are basically what you stated, it'll certainly do the trick.
I have been looking for a solution but couldn't find what I need/want.
All I want to do is pass a stream intended for std::cout to a function, which manipulates it. What I have used so far is a template function:
template<typename T>
void printUpdate(T a){
std::cout << "blabla" << a << std::flush;
}
int main( int argc, char** argv ){
std::stringstream str;
str << " hello " << 1 + 4 << " goodbye";
printUpdate<>( str.str() );
return 0;
}
What I would prefer is something like:
printUpdate << " hello " << 1 + 4 << " goodbye";
or
std::cout << printUpdate << " hello " << 1 + 4 << " goodbye";
I was trying to do:
void printUpdate(std::istream& a){
std::cout << "blabla" << a << std::flush;
}
but that gave me:
error: invalid operands of types ‘void(std::istream&) {aka void(std::basic_istream<char>&)}’ and ‘const char [5]’ to binary ‘operator<<’
You can't output data to an input stream, just not a good thing to do.
Change:
void printUpdate(std::istream& a){
std::cout << "blabla" << a << std::flush;
}
To:
void printUpdate(std::ostream& a){
std::cout << "blabla" << a << std::flush;
}
Note the stream type change.
Edit 1:
Also, you can't output a stream to another stream, at least std::cout.
The return value of << a is a type ostream.
The cout stream doesn't like being fed another stream.
Change to:
void printUpdate(std::ostream& a)
{
static const std::string text = "blabla";
std::cout << text << std::flush;
a << text << std::flush;
}
Edit 2:
You need to pass a stream to a function requiring a stream.
You can't pass a string to a function requiring a stream.
Try this:
void printUpdate(std::ostream& out, const std::string& text)
{
std::cout << text << std::flush;
out << text << std::flush;
}
int main(void)
{
std::ofstream my_file("test.txt");
printUpdate(my_file, "Apples fall from trees.\n");
return 0;
}
Chaining Output Streams
If you want to chain things to the output stream, like results from functions, the functions either have to return a printable (streamable object) or the same output stream.
Example:
std::ostream& Fred(std::ostream& out, const std::string text)
{
out << "--Fred-- " << text;
return out;
}
int main(void)
{
std::cout << "Hello " << Fred("World!\n");
return 0;
}
Alright so i have these two structures, Im sending them down to a function to be saved to a txt file.
struct Cost
{
double hours;
double cost;
double costFood;
double costSupplies;
};
struct Creatures
{
char name[50];
char description[200];
double length;
double height;
char location[100];
bool dangerous;
Cost management;
};
This is the part of the function im confused on, i don't know how to take each line of this structure and write it to the file. Can someone explain to me how to do this?
file.open(fileName, ios::out);
if (!file)
{
cout << fileName << " could not be opened." << endl << endl;
}
else
{
fileName << c.name
<< c.description
<< c.lenght
<< c.height
<< c.location
<< c.dangerious
<< c.management.hours
<< c.management.cost
<< c.management.costFood
<< c.management.costSupplies;
file.close();
cout << "Your creatures where successfully save to the " << fileName << " file." << endl << endl
<< "GOODBYE!" << endl << endl;
}
}
If you want a solution like what you wrote in your question all you need to do is put and end line after each attribute you write out.
fileName << c.name << std::endl
<< c.description << std::endl
...
As long as the information you were trying to output is all that is going in the file this should work.
Then you can read them back in in the order you wrote them. Just be careful when reading back in strings which might have spaces in them.
You need to write the overloaded operator << for your defined classes Cost and Creatures.
class Cost {
public:
friend std::ostream& operator<< (std::ostream& o, const Cost& c);
// ...
private:
// data member of Cost class
};
std::ostream& operator<< (std::ostream& o, const Cost& c)
{
return o << c.hours<<"\t"<<c.cost<<"\t"<<c.costFood<<"\t"<<c.costSupplies<<std""endl;
}
Now you can use it as follows:
Cost c;
std::cout<<c<<"\n";
For detailed information about this concept, you can refer the ISOCPP FAQ link on this
http://isocpp.org/wiki/faq/input-output#output-operator