How to create a "default" stream insertion operator in C++? - c++

I have a class similar to boost::any, in that it is a templated container class. I'd like to have a method to write the contained value to a string. However, if the contained type doesn't provide a stream insertion operator, I'd like my method to return some default tring rather than failing to compile. Below is as close as I've come, and should make it clear as to what I'm trying to do:
namespace W {
namespace hide {
template <typename T>
std::ostream& operator<<(std::ostream& out, const T& t) {
return std::operator<<(out, typeid(T).name());
}
}
template <typename T> struct C {
T t_;
std::string ToString() const {
using namespace hide;
std::ostringstream oss;
oss << t_;
return oss.str();
}
};
}
This works pretty well, with some caveats. For example, if I want to actually provide an overloaded insertion operator for a class, then that operator has to either be in the same namespace as the class, or it has to be in the W namespace for it to be considered.
It also has problems with any type that already has a non-member std::operator<<, e.g. char and std::string. If T is one of those types, then the oss << t_ line above becomes ambiguous. This can be worked around by adding overloads for these types inside the W namespace, for example:
std::ostream& operator << (std::ostream& out, const std::string& s) {
return std::operator <<(out, s);
}
My question is, has anyone found a better method than this? Why do I have to add my own overloads for things like std::string? Is this all supported according to the standard, or am I taking advantage of non-standard behavior? (I am testing with g++ 4.3.3)

Below is some code that I recall seeing a while ago in a compiler construction class. I thought it was particularly clever (if not 'clean') so I held on to it.
From http://www.cs.colorado.edu/~main/a++/tree.h
// If data of type T can be printed with the usual << operator, then
// print<T>(out, p) will interpret *p as a T object and print its
// value to out. Otherwise, a message is printed to out, indicating
// that objects of type T are not printable.
template<typename T> void print(std::ostream& out, const void* p)
{
// The first part of this code sets an enum value, is_printable, to
// be 1 if the data type T can be printed with the usual <<
// operator. Otherwise, is_printable is set to zero. The programming
// technique is based on a note from Herb Sutter at
// http://www.gotw.ca/gotw/071.htm
class object
{
public:
object(T convert) { };
};
char operator << (std::ostream&, const object&);
enum { is_printable = sizeof(std::cout << (*static_cast<T*>(0))) == sizeof(char) ? 0 : 1 };
// Notice that the boolean expression in the if-statement is known at
// compile time, so that only one of the two output statements will be
// compiled into object code.
if (is_printable)
out << *static_cast<const T*>(p);
else
out << "(value of type " << typeid(T).name() << " cannot be printed)";
}
When you construct your container object, hold a pointer to the print function for the variable:
void (*printer)(std::ostream&, const void*);
printer = print<T>;
Then later use the printer() function to display the contained value if possible.
Hope this helps.

Related

Calling << operator on types held in a std::variant?

I've got a struct like this:
// Literal.hpp
struct Literal
{
std::variant<
std::nullptr_t,
std::string,
double,
bool
>
value;
friend std::ostream &operator<<(std::ostream &os, Literal &literal);
};
and I'm trying to implement the << operator like this:
// Literal.cpp
Literal::Literal() : value(value) {}
std::ostream &operator<<(std::ostream &os, const Literal &literal)
{
std::visit(/* I don't know what to put here!*/, literal.value);
}
I've tried implementing the operator like this (note: I would take any elegant solution it doesn't have to be a solution to this implementation below)
// In Literal.cpp
std::ostream &operator<<(std::ostream &out, const Literal literal)
{
std::visit(ToString(), literal.value);
return out;
}
struct ToString; // this declaration is in literal.hpp
void ToString::operator()(const std::nullptr_t &literalValue){std::cout << "null";}
void ToString::operator()(const char &literalValue){std::cout << std::string(literalValue);}
void ToString::operator()(const std::string &literalValue){std::cout << literalValue;}
void ToString::operator()(const double &literalValue){std::cout << literalValue;}
void ToString::operator()(const bool &literalValue){std::cout << literalValue;}
But in my main function, passing a char array literal doesn't casts it into a bool when it runs! ignoring the operator overload taking a char:
main() {
Literal myLiteral;
myLiteral.value = "Hello World";
std::cout << myLiteral << std::endl;
}
This is a bug in your standard library. Presumably you're using libstc++ (the GNU C++ standard library), since that's what Godbolt shows as messing up. If you compile with libc++ (Clang/LLVM's C++ standard library), this works as expected. According to std::vector<Types...>::operator=(T&& t)'s cppreference page, it
Determines the alternative type T_j that would be selected by overload resolution for the expression F(std::forward<T>(t)) if there was an overload of imaginary function F(T_i) for every T_i from Types... in scope at the same time, except that:
An overload F(T_i) is only considered if the declaration T_i x[] = { std::forward<T>(t) }; is valid for some invented variable x;
If T_i is (possibly cv-qualified) bool, F(T_i) is only considered if std:remove_cvref_t<T> is also bool.
That last clause is there for this very situation. Because lots of things can convert to bool, but we don't usually intend this conversion, that clause causes conversion sequences that would not normally be selected to be selected (char const* to bool is a standard conversion, but to std::string is "user-defined", which is normally considered "worse"). Your code should set value to its std::string alternative, but your library's implementation of std::variant is broken. There's probably an issue ticket already opened, but if there isn't, this is grounds to open one. If you're stuck with your library, explicitly marking the literal as a std::string should work:
literal.value = std::string("Hello World");
For the elegance question, use an abbreviated template lambda.
std::ostream &operator<<(std::ostream &os, Literal const &literal)
{
std::visit([](auto v) { std::cout << v; }, literal.value);
// or
std::visit([](auto const &v) {
// gets template param vvvvvvvvvvvvvvvvvvvvvvvvv w/o being able to name it
if constexpr(std::is_same_v<std::decay_t<decltype(v)>, std::nullptr_t>) {
std::cout << "null";
} else std::cout << v;
}, literal.value);
// only difference is nullptr_t => "nullptr" vs "null"
return std::cout;
}
Also, your friend declaration doesn't match the definition. Actually, it shouldn't be friended anyway, since it needs no access to private members.
// declaration in header, outside of any class, as a free function
std::ostream &operator<<(std::ostream&, Literal const&);
// was missing const ^^^^^

How to override ostream << operator for already defined type

I'm currently working on a port of an existing library which makes use of ostream to write to a terminal.
The ostream was derived as part of the port.
The ostream derivative class used is defined as so:
class owstream: public std::ostream {
public:
CTerminal * output;
giac::context * contextptr;
owstream(CTerminal *, giac::context * contextptr , int = 0);
virtual ~owstream();
};
This is used to output some data, typically integers and doubles.
The problem is that the platform I'm working on has a buggy double print routine that causes kernel crash.
So in some cases, if I do:
ostream* mystream = new ostream(...);
(*mystream) << 1.23456
kaboom
so, I tried to override the << operator for certain type, like so:
ostream* GetStream() { return = new MyOStream(...); }
....
ostream* mystream = GetStream()
mystream << 1.23456;
Unfortunately, the operator<< member in ostream isn't virtual so if I created an overridden operator<< member would never be called.
I tried to extend it with something like:
class owstream: public std::ostream {
friend std::ostream& operator<<(std::ostream& out, double val);
public:
CTerminal * output;
giac::context * contextptr;
owstream(CTerminal *, giac::context * contextptr , int = 0);
virtual ~owstream();
};
extern std::ostream& operator<<(std::ostream &out, double val);
But this causes compilation error in regards to operator << being ambiguous, as obviously this is a type already handle by the base iostream class.
I'm starting to wonder if this is at all possible.
How would you implement the << operator to override the behaviour when given a particular, already handled type ?
The aim being able to do something like:
cout << 1.234567
not crashing (I obviously wouldn't be using cout, but GetStream() as defined above, could very well return cout)
I see three problems with your current approach/implementation.
Problem #1
Even if you were to successfully get it to use std::ostream as the first parameter and return value it would not work correctly. The problem stems mainly from returning an ostream from the overloaded operator<<. After the first value has been sent to the owstream all subsequent values get sent to the returned ostream. This puts you right back where you started with the original problem. In order to for this to work properly you need to take owstream as the first parameter and return an owstream in the overloaded operator<<.
Problem #2
Another problem is owstream is implicitly convertible to std::ostream. Depending on how owstream is used in your project there is a possibility that the overloads you provide may not make a difference in certain situations. For instance if an object of type owstream is passed to a function that accepts a std::ostream you may end up encountering the problem you are currently experiencing. You can prevent this from happening by using private inheritance. This will prevent any implicit use of owstream as a std::ostream. Using private inheritance also has the benefit of preventing you from unknowingly using functions in std::ostream which may lead you back to your original problem. For instances where a std::ostream is absolutely necessary you can use an accessor function to explicitly retrieve a reference to it.
Problem #3
The last issue is that std::ostream includes an overload of operator<< that handles std::ostream specific IO manipulators such as std::endl. If you do not provide an overload to specifically handle these the one in std::ostream gets used and once again you end up right back where you started. If you use private inheritance described above and do not provide an overload to handle the manipulators it will fail to compile.
Solution
The solution below is similar to the one provided by JRG and includes the accessor function and overloads for double, float, and std::ostream IO manipulators. It is a complete working example and uses the stream buffer from std::cout for simplicity. I included the overload for float as the deficient library implementation may a similar issue with them. It also uses private inheritance to prevent implicit conversions to std::ostream.
I tested it on VC++10 and GCC 4.7.2. You may need to make some adjustments depending on how compliant your compiler and libraries are.
#include <ostream>
#include <iostream>
#include <sstream>
class owstream : private std::ostream
{
public:
owstream(std::streambuf* sb)
: std::ostream(sb)
{}
// Template based operator...ohhhhhh ahhhhh.
template <typename T>
friend owstream& operator<<(owstream&, const T&);
// Additional overload to handle ostream specific io manipulators
friend owstream& operator<<(owstream&, std::ostream& (*)(std::ostream&));
// Accessor function to get a reference to the ostream
std::ostream& get_ostream() { return *this; }
};
template <typename T>
inline owstream&
operator<<(owstream& out, const T& value)
{
static_cast<std::ostream&>(out) << value;
return out;
}
// overload for double
template <>
inline owstream&
operator<<(owstream& out, const double& value)
{
std::stringstream ss;
ss << value;
return out << ss.str();
}
// overload for float
template <>
inline owstream&
operator<<(owstream& out, const float& value)
{
std::stringstream ss;
ss << value;
return out << ss.str();
}
// overload for std::ostream specific io manipulators
inline owstream&
operator<<(owstream& out, std::ostream& (*func)(std::ostream&))
{
static_cast<std::ostream&>(out) << func;
return out;
}
int main()
{
owstream ows(std::cout.rdbuf());
ows << std::endl;
ows << "hello " << 1.0 << " " << 2.0f << std::endl;
}
What about something like this:
template <typename T>
owstream& operator<<(owstream&, const T&);
template <typename T>
inline owstream&
operator<<(owstream& os, const T& val)
{
std::ostream& stdos = static_cast<std::ostream&>(os);
stdos << val;
return os;
}
template <>
inline owstream&
operator<<(owstream& os, const double& val)
{
std::stringstream ss;
ss << val;
os << ss.str();
return os;
}

derived basic_ostream: "using" keyword and ambiguous overload for operator <<

I have a derived basic_ostream class and an inline modifier (similar to setw). My stream class should also inherit all the operator << behavior from its parent. I get different compiler errors depending on whether I use the "using" keyword or not:
#include <iostream>
struct modifier { };
template <typename C, typename T=std::char_traits<C> >
struct mystream : public std::basic_ostream<C, T>
{
// this is where the trouble is
using std::basic_ostream<C, T>::operator <<;
inline mystream & operator << (const modifier & mod)
{
// ...custom behavior...
return *this;
}
};
int main()
{
mystream<char> foo;
modifier m;
foo << "string"; // this fails if the using is present
foo << 123; // this fails if the using is absent
foo << m;
}
When I put the using directive in, the compiler is confused about the "string" output, and if I comment it out, it gets confused about the integer 123 output, in both cases giving me "error: ambiguous overload for 'operator<<'". I have the problem with both g++ 4.2.1 and g++4.8. What's the right way forward here?
Rather then inherit from std::basic_ostream, won't it be sufficient to just re-implement << for your modifier struct using a regular stream:
std::ostream & operator << (std::ostream &stream, const modifier & mod)
{
// ...custom behavior...
return stream;
}
Your solution seems overcomplicated, but I think the actual error you get comes from your overload of << - it has to accept two arguments (first argument being reference to stream itself).
Without the using, it is clear: the compiler will not find any
of the member overloads of <<, because your function hides
them. The << is a member, so without the using, it
disappears. The << is not a member, so it still works.
When you add the using: all of the member overloads are
visible, as if they were members of your class. And
"string" will be converted to a char const*. The overload
that the compiler is trying to resolve is:
operator<<( mystream<char>, char const* ).
Now consider some of the overloads to be considered:
std::ostream& mystream::operator<<( void const* );
std::ostream& mystream::operator<<( bool );
std::ostream& operator<<( std::ostream&, char const* );
For the first argument (foo, a mystream), the first two
functions are both better matches than the third (since they are
an exact match); for the second argument (the string literal),
the third function is a better match. Thus: ambiguous.
More generally, there are several problems with your code.
Fundamentally, you do not add << operators by deriving. As
you see, it doesn't work. Perhaps more significantly, something
like:
foo << 123 << m;
will not work, because foo << 123 returns a std::ostream&,
not a mystream, and there is no << which will work with an
std::ostream& and a modifier. You add << operators by
defining new free functions:
std::ostream&
operator<<( std::ostream& dest, modifier const& other )
{
// ...
return *this;
}
If you need additional data to format, you use xalloc and
iword or pword to get it, e.g. to define a manipulator:
static int Modifier::modIndex = std::ostream::xalloc();
class mod1
{
int myModifier;
public:
mod1( int m ) : myModifier( m ) {}
friend std::ostream& operator<<( std::ostream& dest,
mod1 const& mod )
{
dest.iword( modIndex ) = myModifier;
return *this;
}
};
You then access dest.iword( modIndex ) to get this information
in the output routine.
iword() returns a long&, different for each instance of your
stream (and for each different index you use).
If you need more information, you can use pword instead of
iword—pword returns a reference to a void*. If you
want use it to point to dynamically allocated memory, don't
forget to register a callback to delete it (using
ios_base::register_callback).

Operator overloading c++ (<<)

This the below program i have written for some test.
class tgsetmap
{
public:
std::map<std::string,std::string> tgsetlist;
void operator<<(const char *str1,const char *str2)
{
tgsetlist.insert( std::map<std::string,std::string>::value_type(str1,str2));
}
};
int main()
{
tgsetmap obj;
obj<<("tgset10","mystring");
obj.tgsetlist.size();
}
This throws a compilation error:
"test.cc", line 10: Error: Illegal number of arguments for tgsetmap::operator<<(const char, const char*).
"test.cc", line 22: Error: The operation "tgsetmap << const char*" is illegal.
2 Error(s) detected.*
Am i wrong some where?
You can't force operator<< to take two arguments on right-hand side. The following code:
obj<<("tgset10","mystring");
does not work as a function call with two arguments but instead just uses the , operator. But it's probably not what you are interested in.
If you need to pass two arguments to the << operator, you need to wrap them in some other (single) type. For example, you could use the standard std::pair, i.e. std::pair<const char*, const char*>.
But note that the operator<< should also return some reasonable type suitable for << chaining. That would probably be a tgsetmap& in your case. The following version should work fine:
#include <map>
#include <string>
#include <iostream>
class tgsetmap
{
public:
typedef std::map<std::string, std::string> list_type;
typedef list_type::value_type item_type;
list_type tgsetlist;
tgsetmap& operator<<(item_type item)
{
tgsetlist.insert(item);
return *this;
}
};
int main()
{
tgsetmap obj;
obj << tgsetmap::item_type("tgset10","mystring")
<< tgsetmap::item_type("tgset20","anotherstring");
std::cout << obj.tgsetlist.size() << std::endl;
}
Note that I've added typedefs to not have to repeat the type names over and over again. I've also made operator<< return a tgsetmap& so that << could be chained (used like in the modified main() above). And finally, I've reused the std::map<...>::value_type to make it simpler but you could also use any other type of your own.
But I believe that you may prefer using a regular method instead. Something like:
void add(const char *str1, const char *str2)
{
tgsetlist.insert( std::map<std::string, std::string>::value_type(str1, str2));
}
(inside the class declaration), and then:
obj.add("tgset10", "mystring");
The operator<< inside of a class must be overloaded like this:
T T::operator <<(const T& b) const;
If you want to overload it with 2 arguments, you can do it outside of a class:
T operator <<(const T& a, const T& b);
My compiler, for example, gives a more detailed error message for the code you posted:
If you are not sure about an operator overloading syntax, there is a wiki article about it.
Yes. operator << is binary operator. not ternary. not forget about this pointer.
As mentioned, the << is binary operator, so there is no way it can take more than two args(One should be this if you are declaring inside the class or a LHS if you are declaring outside the class). However you can accomplish the same functionality by doing obj<<"tgset10". <<"mystring";. But since << is a binary operator, you have to do some hack for this.
For this, I ve assigned a static variable op_count, where in I will determine if it is the value or the type. And another static variable temp_str to store the previous value across invocations.
class tgsetmap
{
public:
std::map<std::string,std::string> tgsetlist;
static int op_count = 0;
static const char *temp_str;
tgsetmap& operator<<(const char *str)
{
op_count++;
if (op_count%2 != 0) {
temp_str = str;
}
else {
tgsetlist.insert( std::map<std::string,std::string>::value_type(temp_str,str));
}
return this;
}
};
So you can do
int main()
{
tgsetmap obj;
obj<<"tgset10"<<"mystring";
obj.tgsetlist.size();
}
Or simply you can embed the value and type in the same string using some separator,
value:type = separator is :
value_type = separator is _.

Unable to find operator via implicit conversion in C++

When writing a class to act as a wrapper around a heap-allocated object, I encountered a problem with implicit type conversion that can be reduced to this simple example.
In the code below the wrapper class manages a heap-allocated object and implicitly converts to a reference to that object. This allows the wrapper object to be passed as the argument to the function write(...) since implicit conversion takes place.
The compiler fails, however, when trying to resolve the call to operator<<(...), unless an explicit cast is made (checked with MSVC8.0, Intel 9.1 and gcc 4.2.1 compilers).
So, (1) why does the implicit conversion fail in this case? (2) could it be related to argument-dependent lookup? and (3) is there anything that can be done to make this work without the explicit cast?
#include <fstream>
template <typename T>
class wrapper
{
T* t;
public:
explicit wrapper(T * const p) : t(p) { }
~wrapper() { delete t; }
operator T & () const { return *t; }
};
void write(std::ostream& os)
{
os << "(1) Hello, world!\n";
}
int main()
{
wrapper<std::ostream> file(new std::ofstream("test.txt"));
write(file);
static_cast<std::ostream&>( file ) << "(2) Hello, world!\n";
// file << "(3) This line doesn't compile!\n";
}
It fails because you're trying to resolve an operator of your wrapper<T> class that doesn't exist. If you want it to work without the cast, you could put together something like this:
template<typename X> wrapper<T> &operator <<(X &param) const {
return t << param;
}
Unfortunately I don't know of a way to resolve the return type at compile time. Fortunately in most cases it's the same type as the object, including in this case with ostream.
EDIT: Modified code by suggestion from dash-tom-bang. Changed return type to wrapper<T> &.
The compiler doesn't have enough context to determine that operator& will make a valid conversion. So, yes, I think this is related to argument-dependent lookup: The compiler is looking for an operator<< that can accept a non-const wrapper<std::ostream> as its first parameter.
I think the problem has to do with maintaining some compile-time constraints. In your example, the compiler first would have to find all the possible operator<<. Then, for each of them, it should try if your object could be automatically converted (directly or indirectly) to any of the types that each operator<< are able to accept.
This test can be really complex, and I think this is restricted to provide a reasonable compiling time.
After some testing, an even simpler example identifies the source of the problem. The compiler cannot deduce the template argument T in f2(const bar<T>&) below from implicit conversion of wrapper<bar<int> > to bar<int>&.
template <typename T>
class wrapper
{
T* t;
public:
explicit wrapper(T * const p) : t(p) { }
~wrapper() { delete t; }
operator T & () const { return *t; }
};
class foo { };
template <typename T> class bar { };
void f1(const foo& s) { }
template <typename T> void f2(const bar<T>& s) { }
void f3(const bar<int>& s) { }
int main()
{
wrapper<foo> s1(new foo());
f1(s1);
wrapper<bar<int> > s2(new bar<int>());
//f2(s2); // FAILS
f2<int>(s2); // OK
f3(s2);
}
In the original example, std::ostream is actually a typedef for the templated class std::basic_ostream<..>, and the same situation applies when calling the templated function operator<<.
Check the signature of the insertion operator... I think they take non-const ostream reference?
Confirmed with C++03 standard, signature of the char* output operator is:
template<class charT, class traits>
basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, const charT*);
which does indeed take a non-const reference. So your conversion operator does not match.
As noted in the comment: this is irrelevant.
There are various limits in the Standard about conversions applied... maybe this would need to implicit conversions (your operator, and cast to base type) when at most one should be applied.