void operator;(){
..etc..
} syslog(LOG_ERR, "The value is %d", value);
syslog(LOG_INFO, "The device is %s", dev); Syslog << Log_Err << "The value is " << value ;
Syslog << Log_Info << "The device is " << dev ;
struct CoutLn
{
// Typical inserter function.
CoutLn& operator<<(const char* x)
{
cout << x;
return *this;
}
// Terminator operator.
// Send a newline to the console at
// statement termination.
void operator;()
{
cout << '\n';
}
// Manipulator to ignore the next
// terminator.
const static struct SkipNl {} skipnl;
// Return void on SkipNl, thus
// "deactivating" the subsequent
// terminator operator.
void operator<<(const SkipNl){}
} coutln;
int main()
{
coutln << "A" ; // Prints "A\n"
coutln << "B" << CoutLn::skipnl ; // Prints "B"
}
Syslog << Log_Err << "The value is " << value << SLgo; // or any other tag
coutln << "A" ; // Prints "A\n"
coutln << "B" << CoutLn::skipnl ; // Prints "B"
That's more typing than one line with std::endl and one without, but the latter isn't completely inverse (perverse?) to intuition.
The real solution is to use tag structs OR a non-inserting operator/call (that processes a full 'statement' of output at a time a la printf). Neither of which semantically break the language for the sake of saving a few keystrokes in the few situations to which they're barely applicavble.
Maybe I should have waited until April 1st before posting this... but is this a good idea? Seems to be OK to me. If something like this existed decades ago, I would have used it many many times by now (unless there's some "gotcha" I missed)...
Let's put a new operator into C++: the "terminator operator." It would look like this: ';' (a semicolon). It would be a unary postfix operator with a lower precedence than the comma operator.
A class can overload the terminator operator by defining a member function like:void operator;(){
..etc..
}
The purpose of the terminator operator is to perform some action when a sequence of operations reaches the statement terminator. If a terminator operator isn't defined for an object, then nothing special happens.
#include <iostream>
#include <sstream>
#include <iomanip>
using namespace std;
struct Syslog
{
int level;
ostringstream o;
Syslog(int lev):level(lev){}
template<class T>
Syslog& operator<<(const T& x){
o << x;
return *this;
}
~Syslog(){
cout << "Calling ::syslog(" << level << ", \"" << o.str() << "\")" << endl;
}
operator bool (){
return bool(o);
}
};
int main(){
Syslog(1) << "The number is 0x" << hex << 255;
Syslog(2) << "The temp is " << 99.99;
if(Syslog(3) << "Three")
{
Syslog(4) << "Four";
}
else
{
Syslog(5) << "Five";
}
}
/* Prints out:
Calling ::syslog(1, "The number is 0xff")
Calling ::syslog(2, "The temp is 99.99")
Calling ::syslog(3, "Three")
Calling ::syslog(4, "Four")
*/| From: Derek Ross Sent: Saturday, July 16, 2016 4:01 PM To: ISO C++ Standard - Future Proposals Reply To: std-pr...@isocpp.org Subject: [std-proposals] Re: Let's overload the semicolon! |