I'd like to implement a custom manipulator for ostream to do some manipulation on the next item being inserted into the stream. For example, let's say I have a custom manipulator quote:
std::ostringstream os;
std::string name("Joe");
os << "SELECT * FROM customers WHERE name = " << quote << name;
The manipulator quote will quote name to produce:
SELECT * FROM customers WHERE name = 'Joe'
How do I go about accomplishing that?
Thanks.
It's particularly difficult to add a manipulator to a C++ stream, as one has no control of how the manipulator is used. One can imbue a new locale into a stream, which has a facet installed that controls how numbers are printed - but not how strings are output. And then the problem would still be how to store the quoting state safely into the stream.
Strings are output using an operator defined in the std namespace. If you want to change the way those are printed, yet keeping the look of manipulators, you can create a proxy class:
namespace quoting {
struct quoting_proxy {
explicit quoting_proxy(std::ostream & os):os(os){}
template<typename Rhs>
friend std::ostream & operator<<(quoting_proxy const& q,
Rhs const& rhs) {
return q.os << rhs;
}
friend std::ostream & operator<<(quoting_proxy const& q,
std::string const& rhs) {
return q.os << "'" << rhs << "'";
}
friend std::ostream & operator<<(quoting_proxy const& q,
char const* rhs) {
return q.os << "'" << rhs << "'";
}
private:
std::ostream & os;
};
struct quoting_creator { } quote;
quoting_proxy operator<<(std::ostream & os, quoting_creator) {
return quoting_proxy(os);
}
}
int main() {
std::cout << quoting::quote << "hello" << std::endl;
}
Which would be suitable to be used for ostream. If you want to generalize, you can make it a template too and also accept basic_stream instead of plain string. It has different behaviors to standard manipulators in some cases. Because it works by returning the proxy object, it will not work for cases like
std::cout << quoting::quote;
std::cout << "hello";
Try this:
#include <iostream>
#include <iomanip>
// The Object that we put on the stream.
// Pass in the character we want to 'quote' the next object with.
class Quote
{
public:
Quote(char x)
:m_q(x)
{}
private:
// Classes that actual does the work.
class Quoter
{
public:
Quoter(Quote const& quote,std::ostream& output)
:m_q(quote.m_q)
,m_s(output)
{}
// The << operator for all types. Outputs the next object
// to the stored stream then returns the stream.
template<typename T>
std::ostream& operator<<(T const& quoted)
{
return m_s << m_q << quoted << m_q;
}
private:
char m_q;
std::ostream& m_s;
};
friend Quote::Quoter operator<<(std::ostream& str,Quote const& quote);
private:
char m_q;
};
// When you pass an object of type Quote to an ostream it returns
// an object of Quote::Quoter that has overloaded the << operator for
// all types. This will quote the next object and the return the stream
// to continue processing as normal.
Quote::Quoter operator<<(std::ostream& str,Quote const& quote)
{
return Quote::Quoter(quote,str);
}
int main()
{
std::cout << Quote('"') << "plop" << std::endl;
}
[EDIT: "True manipulator semantics" (i.e. a persistent quoting state) could also be achieved by wrapping an std::ostream rather than deriving from it, as noted by BenĂ´it in the comments.]
To the best of my knowledge this cannot be done directly without either deriving a new class from std::ostream or similar, or wrapping such a class in another class that forwards most methods to its contained std::ostream object. That's because, for the code example you provide to work, you will need to somehow modify the behaviour of std::ostream& operator<<(std::ostream&, std::string const&), which is defined somewhere in the iostreams hierarchy (or possibly wherever std::string is defined). You will also need to use the (somewhat ugly) facilities in ios_base to record a boolean flag holding the current quoting state. Look up ios_base::xalloc(), ios_base::iword() and ios_base::pword() to find out how to do that.
However, if you are willing to use the following syntax:
os << "SELECT * FROM customers WHERE name = " << quote(name);
This can be done very simply using a global function (in an appropriate namespace of course).
This syntax has the advantage that quoting is not persistent, meaning it can't "leak out" when a function sets the quote formatting flag and forgets to set it back to its original value.
Or just use OTL which basically already implements a stream interface for SQL very similarly to your example.
Related
My question is: how to define a factory function that takes a parameter and returns a function pointer pointing to a function that is created according to that parameter? (or any other nice way to achieve the same result)
Explanation
In essence, I want to define a factory function set, which takes a std::string parameter str, and returns a pointer to function pf. The function pointer pf points to a function, just created in set, that takes std::ostream & and returns std::ostream &.
In this way, I want to call with std::cout << set(str) << "text" << std::endl;. I hope that the result of set(str) lives at least as long as this statement.
For your reference, it is from cplusplus that
ostream & operator<< (ostream & (*pf)(ostream &));
More Explanation
This is for a real example, shown as below.
First I have manipulators
std::ostream & black(std::ostream & os)
{
return os << "\033[30m"; // make terminal text black
}
std::ostream & red(std::ostream & os)
{
return os << "\033[31m"; // make terminal text red
}
std::ostream & green(std::ostream & os)
{
return os << "\033[32m"; // make terminal text green
}
so that when I call
std::cout << red << "this text is in red" << std::endl;
I will have the desired effect. So far so good.
Now with a map
std::map<std::string, std::string> code =
{
{"black", "30"},
{"red", "31"},
{"green", "32"}
// ...
// could extend much longer as there are many colors
};
I hope to achieve a similar, customized effect with foo("red") with
void foo(std::string str)
{
std::cout << set(str) << ("this text is in " + str) << std::endl;
}
where set takes "red" and looks up the map code for the corresponding code "31".
But I have problems in implementing the set function. I would appreciate it much if anyone could help me with this!
Two notes:
If possible, I want good performance for the set function, as it will be called again and again.
Forgive me please if I think the wrong way --- So long as you can implement the functionality for set, I don't mind you do it in a different way.
Thank you for reading this long post. Thank you very much!
You are thinking the wrong way about it. What you need to do instead is to create you own parameterized manipulator. Such manipulator can be implemented as a separate class for which you have to overload operator<< :
struct set_color
{
std::string name;
explicit set_color(std::string name)
: name(std::move(name)) { }
friend std::ostream & operator<<(std::ostream & os, const set_color &color)
{
if (color.name == "black")
os << "\033[30m";
else if ... // and so on
...
}
}
You can use a map instead to convert name to color code, but the basic idea is that there is no need to create a bunch of functions for this.
Why make things complicated?
std::string_view color_from_name(std::string_view colorName)
{
static const std::map<std::string_view, std::string_view> colors {
{"red"sv, "\033[31m"sv},
{"green"sv, "\033[32m"sv},
{"black"sv, "\033[30m"sv},
};
return colors.at(colorName);
}
int main() {
std::cout << color_from_name("red") << "tada" << color_from_name("green") << "got it\n";
return 0;
}
https://wandbox.org/permlink/nh2qMKoovh2qVlk2
I think you could globally define another overload of operator<< as such:
using Manipulator = std::function<std::ostream&(std::ostream&)>;
std::ostream& operator<< (std::ostream& stream, Manipulator&>& func) {
return func(stream);
}
std::map<std::string, Manipulator> manipulators;
for (const auto& val : data) {
manipulators.emplace(std::pair<std::string, Manipulator>(val.first,
[&](std::ostream& out) -> std::ostream& { return out << "\033[" << val.second << "m"; }
));
}
If you stored a map of strings to lambda functions as your manipulators, you should be able to make your set() function a simple wrapper returning your lambda.
I want to modify cout so that the text is displayed with, say, a 30ms delay between the printing of each character... I can't imagine I am the first person to want to do this using cout, but I also can't find any example of the same.
To be clear, I want to override the stream insertion operator (not overload).
I have already written my own output functions, I want to see if it is possible to modify the standard behavior for an entire solution.
You may do something like:
class MyDelayStream
{
public:
MyDelayStream(std::ostream& os) : os(os) {}
template <typename T>
MyDelayStream& operator <<(const T& t)
{
using namespace std::literals;
std::stringstream ss;
ss << t;
for (auto c : ss.str()) {
std::this_thread::sleep_for(30ms);
os << c;
}
return *this;
}
private:
std::ostream& os;
};
And then use it like:
MyDelayStream s(std::cout);
s << "hello" << 42 << '\n';
The hard (missing) part is manipulator and function as std::endl.
I have a C++ class where I place many std::cout statements to print informative text messages about a mass of signals that this class is handling. My intentition is to redirect these text messages to a function named log. In this function, I have flag named mVerbose which defines if the log text should be printed. The content of this function is as follows:
void XXXProxy::log(std::stringstream& ss)
{
if(mVerbose)
{
std::cout << ss;
ss << "";
}
}
Then, the caller code snippet to this function is as follows:
std::stringstream logStr;
logStr << "SE"
<< getAddr().toString()
<< ": WAITING on epoll..."
<< std::endl;
log(logStr);
I would like to overload the << operator in my XXXProxy in a way that I can get rid of creating a std::stringstream object and calling the log function. I want to be able to log the text messages as below and let the << operator aggregate everything into:
<< "SE"
<< getAddr().toString()
<< ": WAITING on epoll..."
<< std::endl;
So I wouldlike to have an member << function that looks like:
void XXXProxy::operator << (std::stringstream& ss)
{
if(mVerbose)
{
std::cout << ss;
ss << "";
}
}
QUESTION
I am relatively a novice C++ developer and get lots of compilation errors when attemting to write the above stated like << operator. Could you please make some suggestions or direct me to some links for me to correctly implement this << operator. Thanks.
If you don't want to use std::cout directly and you want to have your own Log class, you could implement a simple wrapper providing the same interface of std::ostream: operator<<:
class Log {
private:
std::ostream& _out_stream;
//Constructor: User provides custom output stream, or uses default (std::cout).
public: Log(std::ostream& stream = std::cout): _out_stream(stream) {}
//Implicit conversion to std::ostream
operator std::ostream() {
return _out_stream;
}
//Templated operator>> that uses the std::ostream: Everything that has defined
//an operator<< for the std::ostream (Everithing "printable" with std::cout
//and its colleages) can use this function.
template<typename T>
Log& operator<< (const T& data)
{
_out_stream << data;
}
}
So if you implement std::ostream& operator>>(std::ostream& os , const YourClass& object) for your classes, you can use this Log class.
The advantage of this approach is that you use the same mechanism to make std::cout << your_class_object work, and to make the class work with the Log.
Example:
struct Foo
{
int x = 0; //You marked your question as C++11, so in class initializers
//are allowed.
//std::ostream::operator<< overload for Foo:
friend std::ostream& operator<<(std::ostream& os , const Foo& foo)
{
os << foo.x;
}
};
int main()
{
Log my_log;
Foo my_foo;
my_foo.x = 31415;
my_log << my_foo << std::endl; //This prints "31415" using std::cout.
}
Possible improvements:
You could write a extern const of class Log, and make the class implement a singleton. This allows you to access the Log everywhere in your program.
It's common in log outputs to have a header, like Log output (17:57): log message. To do that, you could use std::endl as a sentinel and store a flag that says when the next output is the beginning of a line (the beginning of a log message). Checkout the next answer for a complete and working implementation.
References:
std::ostream
operator<< for std::ostream
std::enable_if
std::is_same
decltype specifier
The timestamp of the example was only that, an example :).
But if you like that, we could try to implement it. Thankfully to C++11 and its STL's big improvements, we have an excellent time/date API: std::chrono
std::chronois based in three aspects:
Clocks
Durations
Time points
Also, chrono provides three types of clocks, std::system_clock, std::steady_clock , and std::high_resolution_clock. In our case, we use std::system_clock (We want access to the date-time, not meassuring precise time intervals).
For more info about std::chrono, checkout this awsome Bo Qian's youtube tutorial.
So if we have to implement a time stamp for our log header, we could do this:
EDIT: Like other good things, C++ templates are good tools until you overuse it.
Our problem was that std::endl is a templated function, so we cannot pass it directly to
annother templated function as parammeter (operator<< in our case), because the compiler cannot deduce std::endl template argumments directly. Thats the recurrent error "unresolved overloaded function type".
But there is a much simpler way to do this: Using an explicit overload of operator<< for std::endl only, and other templated for everything else:
class Log
{
private:
std::ostream& _out_stream;
bool _next_is_begin;
const std::string _log_header;
using endl_type = decltype( std::endl ); //This is the key: std::endl is a template function, and this is the signature of that function (For std::ostream).
public:
static const std::string default_log_header;
//Constructor: User passes a custom log header and output stream, or uses defaults.
Log(const std::string& log_header = default_log_header , std::ostream& out_stream = std::cout) : _log_header( log_header ) , _out_stream( out_stream ) , _next_is_begin( true ) {}
//Overload for std::endl only:
Log& operator<<(endl_type endl)
{
_next_is_begin = true;
_out_stream << endl;
return *this;
}
//Overload for anything else:
template<typename T>
Log& operator<< (const T& data)
{
auto now = std::chrono::system_clock::now();
auto now_time_t = std::chrono::system_clock::to_time_t( now ); //Uhhg, C APIs...
auto now_tm = std::localtime( &now_time_t ); //More uhhg, C style...
if( _next_is_begin )
_out_stream << _log_header << "(" << now_tm->tm_hour << ":" << now_tm->tm_min << ":" << now_tm->tm_sec << "): " << data;
else
_out_stream << data;
_next_is_begin = false;
return *this;
}
};
const std::string Log::default_log_header = "Log entry";
This code snippet works perfectly. I have pushed the complete implementation to my github account.
Reference:
std::chrono
std::chrono::system_clock
std::chrono::system_clock::now()
std::time_t
std::chrono::system_clock::to_time_t()
std::tm
std::localtime()
I am using a template function and I am passing and I may be sending instances of a variety of classes to a string stream. What can I do to make sure this continues to work?
Let me be more specific where do I define the behavior for this? Is there some member that should be on each class being sent to the string stream, should I in some enhance or extend the existing String stream (I was thinking building a class that inherits from sstream and overloads the << operator to handle all the possible classes)?
I had trouble even finding documentation on this, so even links to more resources would be helpful.
It sounds to me like you want to make stream insertion operators. for a class you want to be able to output to a stream, define the free function:
std::ostream& operator<<(std::ostream& stream, const SomeClassType& x)
{
stream << x.someData();
return stream;
}
So if we have SomeClassType z;, and we do std::cout << z (or any other output stream, like an fstream or stringstream), the compiler will look for and find our function, and call it. That is, std::cout << z becomes operator<<(std::cout, z) and inside there you output what you need.
You just need to overload operator<< for those classes, e.g.
struct Point { int x, y; };
std::ostream& operator<<(std::ostream& os, const Point& p)
{
return os << '(' << p.x << ", " << p.y << ')';
}
then you can use it in your function, which might be something like this:
template <class T>
std::string to_string(const T& x)
{
std::stringstream ss;
ss << x;
return ss.str();
}
int main()
{
Point p = {1, 2};
std::string ps = to_string(p);
std::cout << ps << std::endl; // (1, 2)
}
I am trying to write a simple audit class that takes input via operator << and writes the audit after receiving a custom manipulator like this:
class CAudit
{
public:
//needs to be templated
CAudit& operator << ( LPCSTR data ) {
audittext << data;
return *this;
}
//attempted manipulator
static CAudit& write(CAudit& audit) {
//write contents of audittext to audit and clear it
return audit;
}
private:
std::stringstream audittext;
};
//to be used like
CAudit audit;
audit << "Data " << data << " received at " << time << CAudit::write;
I recognise that the overloaded operator in my code does not return a stream object but was wondering if it was still possible to use a manipulator like syntax. Currently the compiler is seeing the '<<' as the binary right shift operator.
Thanks for any input,
Patrick
To make it work you have to add overload of operator << for functions,
than call the function from it:
class CAudit
{
//...other details here as in original question
CAudit& operator << (CAudit & (*func)(CAudit &))
{
return func(*this);
}
};
CAudit audit;
audit << "some text" << CAudit::write;
Binary shift operator and stream operator is the same operator. It is completely legal to overload operator+ for your class to write "Hello world" on std::cout (although it is a very bad idea). The same way C++ standard authors decided to overload operator<< for streams as writing to the stream.
You didn't write clearly what is your problem. My guess is compilation error. The best thing in this case is to quote the error message. If I am right, the problem is, that you defined only operator<< for LPCSTR, and then you want it to work function object on the right side.
You use word "manipulator", but you misunderstand something. Manipulator for a stream (stream from STL) is a function that performs some actions on the stream it is written to. And it works only because of this overload:
ostream& operator<< (ostream& ( *pf )(ostream&));
which takes a function and applies it to a stream.
Similarly you need:
CAudit& operator<< (CAudit& ( *pf )(CAudit& audit))
{
return (*pf)(audit);
}
Wouldn't this
class CAudit
{
public:
template< typename T >
CAudit& operator<<( const T& data )
{
audittext << data;
return *this;
}
class write {};
void operator<<( const write& data )
{
/* whatever */
}
private:
std::stringstream audittext;
};
do what you want?
I do something very similar for tracing, but use a stringstream. This ensures that all 3rd party operator << () and manipulators work. I also use the desctructor instead of the customer write manipulator.
class DebugStream
{
public:
DebugStream(short level, const char * file, int line) {
sstream << "L" << level << "\t" << file << "\t" << line << "\t";
}
~DebugStream() { write(sstream.str()); }
std::ostream & stream() { return sstream; }
private:
std::stringstream sstream;
DebugStream(const DebugStream &);
DebugStream & operator=(const DebugStream &);
};
This is then made available with some macros:
#define DBG_ERROR if (1<=dbg_level()) DebugStream(1, __FILE__, __LINE__).stream()
#define DBG_INFO if (2<=dbg_level()) DebugStream(2, __FILE__, __LINE__).stream()
And the code just uses the macros
DBG_INFO << "print some debug information";
You don't need a specific write manipulator to flush the data to the log file. When the anonymous DebugStream object goes out of scope (once control leaves the line) the the contents are automatically written.
Although I usually avoid macros in this case the use of the if statement means you don't have the overhead of building the trace line unless you actually require it.
Returning the ostream via the stream() method enables this to work for global member functions, as anonymous objects cannot be passed as non-const reference parameters.