Overloading insertion operator in Boost.Log (Boost 1.60.0) - c++

I am trying to overload operator<< so that I can log vector<T>s in Boost.Log. I tried overloading the formatting_ostream:
template <typename T>
inline boost::log::formatting_ostream &
operator<< (boost::log::formatting_ostream & o, const std::vector<T> & v) {
return o;
}
This does not compile with Boost 1.60.0
I am using the following logger:
typedef boost::log::sources::severity_logger<
boost::log::trivial::severity_level
> my_logger_t;
The errors that I see are:
.../boost_1_60_0/build/include/boost/log/utility/formatting_ostream.hpp:799:19:
error: no match for operator<< (operand types are
boost::log::v2s_mt_posix::basic_formatting_ostream<char>::ostream_type
{aka std::basic_ostream<char>} and const std::vector<int>)
strm.stream() << value
As I understand, the overloading doesn't work!!
Because the compiler is still calling the pre-defined operator<< which makes the strm.stream() << value call.
Am I doing something wrong?
What's the best way to go about this?
Thanks!

This looks like an ADL problem: since operator<< is in neither boost::log nor the std namespaces, it doesn't get picked up during name lookup.

Related

Implicit Conversion Operator for Class Objects to Strings [duplicate]

This question already has an answer here:
Why cannot use cout with user-defined conversion to std::string?
(1 answer)
Closed 2 years ago.
I'm learning more about implicit conversion operators, and I've noticed something strange with implicit user-defined conversions for strings. Found below is the code.
#include <iostream>
#include <string>
using std::cout;
using std::endl;
using std::string;
class A {
public:
A() {
*value = "YIKERS";
}
operator string&() {
return *this->value;
}
string* value;
};
int main() {
A abc;
cout << abc << endl;
// compile error: invalid operands to binary expression ('std::__1::ostream' (aka
// 'basic_ostream<char>') and 'A')
return 0;
}
Any ideas as to why I'm getting this compilation error? I'm thinking this could mean that the object isn't being implicitly converted to a string? If so, why not? Is there a way to fix this? The conversion operator works perfectly fine for other data types like int, float, char, etc.
First of all, I think you're not using std::string value as intended. This causes another compile error (at least on gcc 10.2).
It seems like you want a string and you're using a pointer to a string.
This can be fixed by replace string* value with string value, operator string&() with operator string() and *value = "YIKERS' with value = "YIKERS". For the last one you might also want to check initializer lists.
Regarding the current compile error:
The compile error is caused by the code cout << abc trying to use operator<< on an abc which is an object of type A. However, you did not overload this operator.
In your example this could be something like
friend std::ostream &operator<<(std::ostream &output, const A &a )
{
output << a.value;
return output;
}
Even if you have a user-defined conversion to std::string you would still get compile time errors. This link explains it better than I think I could Why cannot use cout with user-defined conversion to std::string?
This is how I understand the explanation from link above:
string header defines the following overload for operator<< for std::basic_ostream:
template <class CharT, class Traits, class Allocator>
std::basic_ostream<CharT, Traits>&
operator<<(std::basic_ostream<CharT, Traits>& os,
const std::basic_string<CharT, Traits, Allocator>& str);
Also, std::string is actually a typedef for std::basic_string<char>.
However, if the conversion is implicit the following rule kicks in:
Type deduction does not consider implicit conversions (other than type
adjustments listed above): that's the job for overload resolution,
which happens later.
So, the compiler cannot deduce the second parameter for the function (e.g. const std::basic_string<CharT, Traits, Allocator>& str) from A. It can, however, deduce it for string so you can explicitly convert abc to string like static_cast<string>(abc) and that would work.

Explicitly calling templated overload of operator<< gives error

I have the following code:
//.hpp
enum class UIDCategory
{
GoodType //and others
};
typedef unsigned short UID;
typedef UID GoodType;
template<UIDCategory UIDCat> //Yes, UIDCat is supposed to go unused
inline std::ostream& operator<<(std::ostream& str, const UID& uid)
{
return str << uid;
}
std::ostream& operator<<(std::ostream& str, const Recipe::GoodRatio& goodRatio);
//definition of Rules here
template<>
inline std::ostream& operator<< <UIDCategory::GoodType>(std::ostream& str, const GoodType& goodType)
{
return str << Rules::goods.at(goodType);
}
//.cpp
std::ostream& operator<<(std::ostream& str, const Recipe::GoodRatio& goodRatio)
{
return str.template operator<< <UIDCategory::GoodType>(goodRatio.goodType);
}
I am using VC++17.
I get the following error on the line in the function in the .cpp file:
Rules.cpp(21): error C2677: binary '<': no global operator found which takes type 'UIDCategory' (or there is no acceptable conversion)
I have been searching the web for a solution and I found out that the template keyword is necessary in the call to operator<< <UIDCategory::GoodType>(goodRatio.goodType) to denote that operator<< is actually a template so I added it as shown but the error doesn't go away. What am I doing wrong here?
The whole idea here is to provide a work-around for the limitation that typedefs do not introduce a new type and therefore cannot be used in overload resolution. I ran into trouble when I simply introduced the following overload: std::ostream& operator<<(std::ostream& str, const GoodType& goodType). This header is equivalent to std::ostream& operator<<(std::ostream& str, const unsigned short& goodType) and so str << aGoodTypeis ambiguous (it clashes with the one in std).
My code is an attempt to enable the user to explicitly state what 'overload' of the << operator is to be used by making a templated overload of the << operator and then explicitly specializing it for the different members of UIDCategory.
I'd appreciate any help on both the error and on the thing that I'm trying to achieve.
While making my Minimal, Complete, and Verifiable example as suggested by Jonas I actually solved the problem. The problem was that I was using the wrong calling convention of the << operator.
I called it as if it is a member of the stream while it isn't.
So it should be operator<<<UIDCategory::GoodType>(str, goodRatio.goodType) instead of str.template operator<< <UIDCategory::GoodType>(goodRatio.goodType).
Also I decided that this is way to convoluted anyway for what I was trying to achieve and chose a simpler method with some minor drawbacks.

Why does operator>> (or <<) overloading function need to receive an i\ostream reference?

From cplusplus.com, I saw that ostream class's member function operator<< looks like this:
ostream& operator<< (bool val); ostream& operator<< (int val);
.... and so on.
It does make sense because when you use the Cout object like cout<<x you activate the ostream& operator<< (int val) function, so you actually use the << operator on Cout object. This is very much like every other operator and sends the int variable to the function. What is the difference and what exactly happens when I want to stream an object of my own? Why does the syntax is suddenly ostream& operator<< (**ostream &os**, object ob)?
Why do I need to add the ostream var? I am still using cout<<ob so whay isnt it just ostream& operator<< (object obj)? All I pass is my object. The cout object is allready there.
operator<< is generally defined as a free function; that is, not a member function. Since it is an overloaded binary operator, that means it get's its left argument first and its right argument second.
The operator<< traditionally returns a reference to its left argument to enable the idiomatic chain of output.
To make it obvious to the reader, I tend to define my operator overloads using the lhs and rhs abbreviations; an operator<< would look similar to this, for some type T.
std::ostream& operator<<(std::ostream& lhs, T const& rhs)
{
// TODO: Do something
return lhs;
}
As a member function
As with other binary it could be defined as a member function. That is, let us suppose that you with defining your own iostream. Amongst other things, your class declaration may look like this. Again, T is a particular type.
class MyIOStream : public iostream
{
public:
MyIOStream& operator<<(T const& rhs);
}
In this case operator<< is a member function. It has the same semantics when used as <<.
References
Operators in C and C++ - a great summary of all the operators you can overload and their typical arguments.
why do I need to add the ostream var?
I'm sure it's there so that you can chain outputs together:
cout << foo << bar
The first call, cout << foo will result in an ostream reference that can be used for the << bar part.
Some of the stream extractors are members of basic_istream; because they are members, the basic_istream argument is implied. Some of the stream extractors are not members of basic_istream. Because they are not members, the basic_istream argument has to be part of the declaration.
Like this (oversimplified):
class basic_istream {
public:
basic_istream& operator>>(int& i);
}
basic_istream& operator>>(basic_istream&, std::string& str);
Both can be called in the same way:
int i;
std::cin >> i; // calls basic_istream::operator>>(int&)
std::string str;
std::cin >> str; // calls operator>>(basic_istrea&, std::string&)

ADL can't locate stream operator with appropriate qualifiers for a user defined type

I'm compiling an x64 service on Microsoft Windows 7 with Visual Studio 2010, using a Boost variant something like:
namespace my_ns
{
typedef struct {} empty_t;
typedef std::pair<size_t, std::shared_ptr<char>> string_t;
typedef boost::variant<empty_t, double, long, string_t> variant_t;
typedef std::map<unsigned short, variant_t> variant_map_t;
}
The day I get rid of that string_t and replace it with an std::string is the day I buy my boss and the team donuts. But that's not why we're here...
The Boost variant supports the stream operators for its containted types provided the type has an overload. So I have:
namespace my_ns
{
std::ostream &operator<<(std::ostream &, const empty_t &);
std::ostream &operator<<(std::ostream &, const string_t &);
}
And yet, I am plagued with the error message:
error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'const T3' (or there is no acceptable conversion)
T3 refers to the string_t.
The offending code generating the error exists in the following context. It's verbose so you, the reader, have relevant context information:
namespace my_ns
{
void Widget::public_method(std::ostringstream &os) const
{
//variant_map_t Widget::the_map; // Private Widget member.
// This here is a C++11 lambda in a standard loop algorithm, if you didn't recognize the syntax.
std::for_each(the_map.begin(), the_map.end() [&os](variant_map_t::value_type value)
{
os << value.first << '=' << value.second << ' ';
});
}
}
I have attempted removing the right hand qualifiers and reference, thinking passing a copy by value would knock off the qualifiers (probably not so brilliant in light of a shared pointer), and I've tried moving the declarations from the namespace to global scope, hoping ADL would pick it up for some reason (I get ADL, conceptually, but there's still just that little bit of black magic to it for me).
I don't know what else to do. What is the nature of this bug beyond the compiler is unable to locate an insertion operator with a const qualified rhs? How can that be, when it's right there? And what is the resolution?
It doesn't help that you add a typedef to your namespace, std::pair and std::ostream are still part of the std namespace. So the compiler will look there for the << operator, and not in your namespace.

C++ overloading

The following code is giving me a compilation error. Can anyone please tell me why?
class mytype {
public:
int value;
mytype(int a) {
value = a;
}
friend ostream& operator<<(ostream& stream, const mytype& a) {
stream << a.value;//works
return stream;
}
friend ostringstream& operator<<(ostringstream& stream, const mytype& a) {
stream << (a.value);//compilation error
return stream;
}
};
Error:
error C2027: use of undefined type
'std::basic_ostringstream<_Elem,_Traits,_Alloc>'
Upon fixing that:
error C2666: 'operator <<' : 18 overloads have similar conversions
Final fix:
Declare constructor as explicit. Works on MSVC then.
I wonder why.
error C2027: use of undefined type 'std::basic_ostringstream<_Elem,_Traits,_Alloc>'
You need #include <sstream> to get the [i/o]stringstream classes.
About the other errors
The problem with an overload of the form
ostringstream& operator<<(ostringstream& stream, const mytype& a)
is that it matches an ostringstream exactly. Why is it a bad thing to have a more exact overload? From the standard, §13.3.3/1-2:
a viable function F1 is defined to be a better function than another viable function F2 if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(F2) …
If there is exactly one viable function that is a better function than all other viable functions, then it is the
one selected by overload resolution; otherwise the call is ill-formed
Therefore if operator<<( ostream &, int ) and operator<<( ostringstream &, mytype const & ) are both candidates for stream << value, the former matches int exactly with no conversion but the latter matches ostringstream exactly. Therefore neither can be "not worse" for all arguments, and neither candidate may be chosen.
But the code is valid because of a loophole. Your overload is not a candidate at all, except when you actually use your type in the function call. When you declare/define a friend inside a class block, it does not introduce it to any namespace scope; it merely associates it with the class scope, which allows it to be found if that class type describes one of the arguments being passed.
The standard has this to say about friend declarations, although it's in another section (14.6.5):
Friend declarations do not introduce new names into any scope…
So, MSVC tried to be nice and proactively introduced your friend to its enclosing namespace. Strike against MSVC.
However, when I attempted to add a declaration equivalent to what MSVC did "for free," Comeau and GCC nicely resolved the resulting overloading conflict — strike against them. Or is it? As it turns out, the overloaded call occurs earlier in the file than my recommended declaration. If I move the declaration before class mytype { (which requires forward-declaring mytype), then both properly complain about the ambiguity.
Using an overload before it is declared in namespace scope appears to be well and good according to §3.3-3.4 of the Standard. So actually GCC and Comeau were both in the right. The point of declaration is right after the name of the declared object. (And last I checked, self-referential function declarations can still crash GCC.) ADL invokes unqualified lookup into the enclosing namespace at a point immediately before the enclosing class. (3.4.1/8 final bullet, 3.4.1/9, 3.4.2/2a.) If the friend hasn't been declared before the class, it's legitimately not a candidate. (7.3.1.2/3) Isn't C++ a beautiful language?
How keep the simplified example on GCC, but break subsequent code.
friend ostringstream& operator<<(ostringstream& stream, const mytype& a) {
stream << (a.value);//compilation error
return stream;
}
};
ostringstream& operator<<(ostringstream& stream, const mytype& a); // <- here
Following this declaration, it will be impossible to write an int into an ostringstream.
How to break everything uniformly, with simpler declaration semantics.
class mytype; // <- here
// and here:
inline ostringstream& operator<<(ostringstream& stream, const mytype& a);
class mytype {
public:
Following this declaration, it will be impossible to write an int into an ostringstream… including the friend declarations inside class mytype {}.
Actual solution.
The stream classes are supposed to be indistinguishable. If you really want to determine whether a given stream feeds a string in memory (and you shouldn't), it's best to look at its internal streambuf object, returned by rdbuf(), which actually performs the I/O gruntwork. Even a generic ostream object can have ostringstream functionality if given a stringbuf.
if ( typeid( stream.rdbuf() ) == typeid( stringbuf * ) ) {
// this is effectively a stringstream
} else {
// not a stringstream
}
There is an overload ambiguity in the call to operator<< in the ostringstream overload.
stream << a.value;
There are a number of operator<< overloads that are members of the ostream class, which is a base class of ostringstream. One of these is declared as:
ostream& ostream::operator<<(int);
This overload is an exact match for the right-hand side (a.value is an int) but requires a derived-to-base conversion on the left-hand side (stream is an ostringstream, which is derived from ostream).
However, there is also your ostringstream overload:
ostringstream& operator<<(ostringstream&, const mytype&);
This overload is an exact match for the left-hand side (stream is an ostringstream), and a user-defined converting constructor (your mytype(int) constructor) can be used to convert a.value (an int) to a mytype.
Since one overload matches the first argument better and the other overload matches the second argument better, there is an ambiguity. You can fix this either by:
Explicitly converting the left-hand side to an ostream (using (ostream&)stream = a.value;), or
Remove the user-defined conversion by making the constructor explicit.