How to overload 2 versions of operator<< in a C++ class - c++

I am overloading operator<< as follows :
std::ostream& operator<<(std::ostream& o, const MyClass& myobj);
Now, I would like to have 2 versions of operator<<, one that would display a short description of my object, and another that would display a longer version.
For example, MyClass could contain information about a client. In the short version I would display just the name, and in the long version I would display more details like birthday, address, etc.
Is there a way to do that in C++ ?
I know I could have a method of MyClass that receives the stream, but it would be called like this :
myObj.DisplayShort(cout)
or
myObj.DisplayLong(cout)
but I would like to stay with a syntax similar to the usual form :
cout << myObj << endl;

The standard way is to create a custom formatting flag and a custom manipulator using std::ios_base::xalloc and std::ios_base::iword.
So you have
class MyClass {
static int fmt_flag_index;
enum fmt_flag { output_short, output_long };
}
You initialize fmt_flag_index somewhere at the program startup:
int MyClass::fmt_flag_index = std::ios_base::xalloc();
Here's your custom formatting flag ready to use. Now IO manipulators can set it:
std::ios_base& myclass_short(std::ios_base& os)
{
os.iword(MyClass::fmt_flag_index) = static_cast<int>(MyClass::output_short);
return os;
}
std::ios_base& myclass_long(std::ios_base& os)
{
os.iword(MyClass::fmt_flag_index) = static_cast<int>(MyClass::output_long);
return os;
}
And operator<< access it:
std::ostream& operator<<(std::ostream& os, MyClass& f)
{
switch (static_cast<MyClass::fmt_flag>(os.iword(MyClass::fmt_flag_index)))
{
case MyClass::output_short: ...;
case MyClass::output_long: ...;
}
}
Use it like this:
MyClass myobj;
std::cout << myclass_long << myobj;
std::cout << myclass_short << myobj;
Demo

I would use a printing adaptor:
class Adaptor
{
MyClass &adaptee;
operator <<
}
And then you can implement different logic based on:
Multiple adapter classes
Single adapter class with a data member
Single adapter class with a template argument

Related

Define a factory function that returns a pointer to a function created in this factory function

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.

C++: Overloading << operator with function pointers

I have a class "stampstream" that is essentially intended to work like 'cout'. The two functions that follow are outside the class. This is the part that works.
class stampstream: public std::ostream
{
//code
stampstream& operator<<(stampstream& (*x)(void))
{
//code
}
//code
};
stampstream& endr()
{
//nocode
}
stampstream& (*endrow)(void)=endr;
In main:
stampstream s;
s << "teststring1" << endrow;
Note that "endrow" is essentially 'endl'. This part works perfectly fine, compiles and executes with the right output.
Now, I'm trying to overload << with another possible row(int) function. This is the part that doesn't work. Again, it's part of the same class as above and the following 2 functions are outside the class.
class stampstream: public std::ostream
{
//code
stampstream& operator<<(stampstream& (*r)(int y))
{
//code
}
//code
};
stampstream& ro(int y)
{
//nocode
}
stampstream& (*row)(int)=ro;
In main:
s << "teststring2" << row(5);
This is the error I get:
error: invalid user-defined conversion from ‘stampstream’ to ‘stampstream& (*)(int)’ [-fpermissive]
What am I doing wrong with row ?
The problem is that in
s << "teststring2" << row(5);
function call has higher precedence than <<, so this calls the function row points at and then tries to pass its return value (a stampstream &) to operator<<.
What you want is
s << "teststring2" << row;
This doesn't call the function and instead passes the pointer to operator<<. Inside that function, when you want to call x, you'll need to provide the argument.
It sounds like what you are trying to do is to have a function row that creates a functor object that you can then pass to operator<<. You can do that in C++11 with a lambda:
class stampstream: public std::ostream
{
//code
stampstream& operator<<(std::function<stampstream&(void)> r)
{
//code
}
//code
};
std::function<stampstream&(void)> row(int x)
{
return [x]()->stampstream & {
//code
}
}
Which you can call as:
s << "teststring2" << row(5);
The call to row happens first, which constructs a lambda and returns it (but doesn't yet run the code in it). The functor is passed to operator<< and when that function calls r, it will call the code in the lambda (which can refer to the x param, which was bound by value, so copied into the lambda.)
Since Chris has already answered your question, I wanted to advise you of alternatives to your current method:
Your stampstream class should use a specialized std::streambuf that writes out the stamp inside overflow(). There's no need to extend an std::ostream and reimplement the input operators. For an example of how to do this, see this thread.
You seem to be using endrow and row like manipulators. Operator overloads already exist for manipulators that do not take arguments at the call site. You can have endrow take and return an object of type std::ostream&. For row you can have it return a class that overloads the inserter to allow the syntax you want:
struct row_impl
{
row_impl(int row) : row(row) { }
// Write out the row and return the stream
friend std::ostream& operator<<(std::ostream& os, row_impl const& rimpl);
private:
int row;
};
std::ostream& operator<<(std::ostream& os, row_impl const& rimpl)
{
// This is where the code for your original row() function goes
}
// write out to and return the stampstream instance
std::ostream& endrow(std::ostream& os);
row_impl row(int row)
{
return row_impl(row);
}
Now s << endrow and s << row(5) will work without having to add anything to your stampstream class.

How does std::cout print a std::string?

Does std::basic_ostream have an overload of operator << that accepts a std::basic_string object? I'm reading cppreference and there doesn't seem to be one listed.
Imagine you create your own class called Car which contains licence plates number, model/power of the engine, and bunch of other information. Now, imagine you want to provide nice way to print your car information into the file, or into the screen.
If you want to use basic_ostream overload, you have no luck, since there is no overload for your class defined. You may provide print_into_ostream method, or some other clever trick, but you've just realized that std::string also doesn't have the appropriate overload, and you still can do cout << myStr;. After a quick search, you find a solution that is applied into the std::string, and you can use it in your class like this:
class Car
{
std::string licence_plate, engine;
public:
// ... other here ...
friend ostream& operator<<(ostream& os, const Car& c);
};
ostream& operator<<(ostream& os, const Car& c)
{
os << c.licence_plate << "-" << c.engine;
return os;
}
And now you can use
cout << myCarObject << endl;
as with any built-in type.
std::string uses the same approach, and you can find documentation here.
There are non-member operators defined in the std namespace. See cppreference.
If you want to print an object of your class A, you overload << operator like this:
ostream & operator << (ostream & os, A &a)
{
os << a.data_member;
}
In the same fashion in the std namespace there is an overloaded operator that prints object of class string.

How to define a static operator<<?

Is it possible to define a static insertion operator which operates on the static members of a class only? Something like:
class MyClass
{
public:
static std::string msg;
static MyClass& operator<< (const std::string& token) {
msg.append(token);
return *this; // error, static
}
};
alternatively:
static MyClass& operator<< (MyClass&, const std::string &token)
{
MyClass::msg.append(token);
return ?;
}
This is how I would like to use it:
MyClass << "message1" << "message2";
Thank you!
What I would probably do in your situation, is create another class that overloads the operator<<, then make a static member of that type. Like this:
class MyClass
{
public:
static std::string msg;
struct Out {
Out & operator<< (const std::string& token) {
MyClass::msg.append(token);
return *this;
}
};
static Out out;
};
Using it is not quite what you asked for, but close enough I think:
MyClass::out << "message1" << "message2";
If all the members of MyClass are static, it's possible to return a fresh instance.
However, returning a reference poses a problem. There are two solutions:
define a static instance
pass by copy, and not by reference.
The second approach is easiest:
static MyClass operator<< (MyClass, const std::string &token)
{
MyClass::msg.append(token);
return MyClass();
}
The first is one line more:
static MyClass& operator<< (MyClass&, const std::string &token)
{
static MyClass instance;
MyClass::msg.append(token);
return instance;
}
Usage is very close to what you want:
MyClass() << "message1" << "message2";
However, I would not recommend to do this. Why don't you just just use a std::ostringstream? You'll get formatting and some more for free. If you really need global access, declare a global variable.
If you want to use your class as cout, what you can do is example
#include <iostream>
using namespace std;
namespace trace
{
class trace
{
public:
trace& operator<< (const std::string& echo)
{
std::cout << echo << std::endl;
return *this;
}
};
trace t; // Note that we created variable so we could use it.
};
using namespace trace; // Note that we use same namespace so we dont need to do trace::t
int main(int argv, char** argc)
{
t << "Server started..."
<< "To exit press CTRL + Z";
return 0;
}
Output should look like each string in new line like this:
Server started...
To exit press CTRL + Z
You can't. A class-name / type is not a value in itself, you would need an expression like
class Foobar {...};
std::cout << Foobar << std::endl;
so that your static operator<< would be usable, but that is not valid C++. The grammar summary at A.4 shows that putting a type's name there is not valid.
Consider also that operator overloads are just functions with flaky names:
T operator<< (T, T)
^^^^^^^^^^ flaky name, basically same as:
T left_shift (T, T)
And functions in C++ (and most other languages, e.g. C#) can only work on instances of types, not types themselves.
However, C++ offers templates which have type arguments, howhowever, that would not help you to overload functions upon types.

Custom manipulator for C++ iostream

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.