问题
I want to replace each cout
occurring in a program with same but concatenated with endl
. I'm trying to use macros for this but unable to figure that out how to do that. Please help!
Is there a way to get complete line written in program and just concat << endl
with it?
Note if endl
is already written by programmer, no endl
will be concatenated.
If any other better method possible, please suggest.
回答1:
Unfortunately, this is possible. But in no sense can I condone it.
#include <iostream>
namespace std
{
class not_actually_cout{};
template<typename T>
not_actually_cout& operator<< (not_actually_cout& stream, const T & v)
{
std::cout << v << std::endl;
return stream;
}
not_actually_cout not_actually_cout_instance;
}
#define cout not_actually_cout_instance
int main(void)
{
cout << "why god why";
cout << "please no";
return 0;
}
Outputs:
why god why
please no
回答2:
Just make a function template:
template<typename T>
void printLn(T const & v, std::ostream & os = std::cout)
{
os << v << std::endl;
}
If you wanna get fancy with it and allow multiple arguments, and C++11 is available to you:
void printLn(std::ostream & os)
{
os << std::endl;
}
template<typename T, typename... Args>
void printLn(std::ostream & os, T const & v, Args&&... args)
{
os << v;
printLn(os, std::forward<Args>(args)...);
}
回答3:
What are you really interested in? The newline after each output operation or the flush? Note that the flush is really expensive, though.
The easiest way to have a flush injected after each output operation is to set the flags std::ios_base::unitbuf
(this is the default setting for std::cerr
):
std::cout << std::unitbuf;
After this operation, you'll get a flush after each individual output operation, e.g.
std::cout << "hello" << ' ' << "world\n";
would cause three flushes. To automatically also insert a newline, you could set up a filtering stream buffer which adds a newline (optionally if there wasn't one) upon flushing the stream. This would amount to overwriting the overflow()
and sync()
functions of a std::streambuf
and installing the corresponding stream buffer into std::cout
in addition to setting std::unitbuf
. With these changes, no source change would be needed.
The code below demonstrates a corresponding filtering stream buffer:
#include <iostream>
#include <streambuf>
class newlinebuf
: public std::streambuf
{
enum { s_size = 64 };
std::ostream& d_stream;
std::streambuf* d_sbuf;
char d_buffer[s_size];
public:
newlinebuf(std::ostream& stream)
: d_stream(stream)
, d_sbuf(stream.rdbuf(this))
{
this->setp(this->d_buffer, this->d_buffer + s_size - 1);
}
~newlinebuf() {
if (this->d_stream.rdbuf() == this) {
this->d_stream.rdbuf(this->d_sbuf);
}
}
int overflow(int c) { // clear the buffer without flushing
std::streamsize size(this->pptr() - this->pbase());
std::streamsize n(this->d_sbuf->sputn(this->pbase(), size));
if (n == 0) { // no progress => error
return std::char_traits<char>::eof();
}
std::copy(this->pbase() + n, this->pbase() + size, this->pbase());
this->setp(this->d_buffer, this->d_buffer + s_size);
this->pbump(size - n);
if (c != std::char_traits<char>::eof()) {
*this->pptr() = std::char_traits<char>::to_char_type(c);
this->pbump(1);
}
return std::char_traits<char>::not_eof(c);
}
int sync() {
if (this->pptr() == this->pbase() || this->pptr()[-1] != '\n') {
*this->pptr() = '\n';
this->pbump(1);
}
return this->overflow(std::char_traits<char>::eof())
== std::char_traits<char>::eof()? -1: 0;
}
};
int main()
{
newlinebuf sbuf(std::cout << std::unitbuf);
std::cout << "hello" << "_" << "world\n" << "next line";
}
Based on the comment I realize that this is probably not what you want but I'm not aware of a portable technique which just uses the preprocessor and/or the compiler to add newlines.
回答4:
Try to use regular expressions. All modern languages has support for them.
Also, for example, if your program not so big, you can try to use SublimeText editor. It has very smart tools for replacement, which supports regex.
来源:https://stackoverflow.com/questions/19103683/replace-coutstring-with-coutstringendl-in-cpp