Explicitly calling templated overload of operator<< gives error - c++

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.

Related

Changing an overloaded operator's signature

An operator can be declared only for the syntax defined for it in the C++ grammar. For example, one can’t define a unary % or a ternary +.
Consider the output operator for a class A. It has the following signature as a non-member:
ostream& operator<<(ostream&, A&);
This signature can't be changed. operator<< is a binary operator. Ie, it can take only 2 arguments.
The same is the case with the corresponding >> operator.
In certain situations, this can be restrictive, since it doesn't give the user of this operator, the required flexibility.
For example, consider a class Money used to store a monetary amount and its output operator:
ostream& operator<<(ostream&, Money&);
Since a monetary value is involved, we need to display the currency symbol also, which could be either the local or international symbol. If the user should be able to specify this, we would need the above operator to have another parameter, say bool intl.
The operator's signature would then be:
ostream& operator<<(ostream&, bool intl, Money&);
Of course, this isn't possible, since the signature is fixed.
How can we proceed in such a situation?
Thanks.
How about making some kind of tag-structure that can be used for overloading the operator? Like e.g.
ostream& operator<<(ostream&, LocalMonetaryType);
Then you can do e.g.
std::cout << LocalMonetaryTypeInstance << YourMoneyObject;
Could be refined so that you use a Money member function to get the tag object, and it then contains the expected symbol to be written.
If a Money is a class it should have a bool intl as a member field. So in that case operator will still have proper definition. It will be even better to define enum for that, example code:
class Money
{
public:
MonetaryEnum localCurrency;
double amount;
friend ostream& operator<< (ostream& os, const Money& m);
}
ostream& operator<<(ostream& os, const Money& m)
{
os << enumToString(localCurrency) << m.getAmount() << std::endl;
return os;
}
and you will be able to provide desired behaviour. It is only example :)

Overloading insertion operator in Boost.Log (Boost 1.60.0)

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.

Understanding streams: how does this function work?

Consider the following function:
template <class T>
void to_string(const T& val, string& s) {
ostringstream o;
o << val;
s = o.str();
}
I'm not sure how this function works. I have two assumptions, please tell me which one is correct (if any):
ostringstream has an overload of operator<< that takes whatever T is (unlikely).
There's a global function with the signature ostream& operator<<(ostream& stream, Sometype& t). This allows a T to be written to the ostringstream, assuming it's a Sometype.
Which one of these is more likely correct? I'm assuming the second one, but I'm not sure.
For some types (most arithmetic ones) there is a member function operator<< in ostream.
For all other types operator<< must be a non-member function with the exact signature that you proposed in your second bullet. Although the second parameter is SomeType const& in most (if not all) cases.

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&)

"recursive on all control paths, function will cause runtime stack overflow" on overloaded << operator

I have a section of code that seems to have a recursive warning when I compile, any ideas why?
ostream& operator << (ostream& out, const node& rhs)
{
out << rhs.get_data();
return out;
}
It is calling this function:
node::value_type node::get_data() const
{
return data;
}
This is just a guess, since you haven't posted a self-contained example. In particular, the definition of node would be very useful.
I think that, for some reason, the compiler is choosing to convert rhs.get_data() into a node, probably using an implicit conversion constructor, rather than selecting an overload of operator<< that takes node::value_type. You should:
Make sure that operator << (ostream&, node::value_type) has been declared before your definition of operator<<
If node has a constructor that takes value_type, then it's probably best to make it explicit to avoid unexpected implicit conversions.