I'm working through an assignment in which I must overload the insertion operator to take a Node object. I've created the operator overload function outside the class definition, but inside the node.h file. Everything compiles fine, but the overloaded operator is not called, instead I get simple the address of the object.
I'm prohibited from modifying the calling code, so any changes must be to the operator overload.
My code as it stands right now:
/** OPERATOR << ***********************************/
template<class T>
inline std::ostream & operator << (std::ostream & out, const Node <T> *& pHead)
{
out << "INCOMPLETE";
return out;
}
Right now, I just want to ensure the overloaded operator is called. I'll fix the output code once I know I'm calling the right operator.
The calling code:
// create
Node <char> * n = NULL;
// code modifying n
// display
cout << "\t{ " << n << " }\n";
Note that the parameter pHead's type is a reference to non-const, const Node<T>* is a non-const pointer to const, the argument n's type is Node<T>* (i.e. a non-const pointer to non-const). Their type doesn't match, Node<T>* need to be converted to const Node<T>*, which is a temporary and can't be bound to reference to non-const.
In short, you can't bind a reference to non-const to an object with different type.
But reference to const could be bound to temporary, so you can change the parameter type to reference to const:
template<class T>
inline std::ostream & operator << (std::ostream & out, const Node <T> * const & pHead)
// ~~~~~
Or change it to passed-by-value, Node<T>* will be implicitly converted to const Node<T>* when passing as argument. (Passing pointer by reference to const doesn't make much sense.)
template<class T>
inline std::ostream & operator << (std::ostream & out, const Node <T> * pHead)
At last, overloading operator<< with pointer type looks weird. The most common form with user-defined type would be:
template<class T>
std::ostream & operator << (std::ostream & out, const Node <T> & pHead)
The problem is that the inserter takes a parameter of type const Node<T>*, but it's called with an argument of type Node<T>*; there is no conversion from T* to const T*. So the "fix" is to remove the const from the stream inserter.
But, as hinted at in a comment, having an inserter that takes a pointer to a type is a bad idea. It should take a const Node<T>&, like all the other inserters in the world. I gather that this is a constraint imposed by an assignment; if so, it's idiotic. You're being taught badly.
Related
The following snippet is simplified version of a logger that I use. It extends std::ostringstream and can be filled using the <<-operator. Upon destruction all content is written to std::cout.
Writing (<<) directly into a temporary object, Logger(), I would expect it to print that input, however, it only prints the address of something on std::cout. When writing into a reference of a temporary object, Logger().stream(), works as expected.
Why is that happening?
Btw, this behavior only occurs in C++98-land (ideone), which I have to use. With C++11 (coliru) and C++14 (ideone) both call variants work as expected. What's different in C++11/14?
#include <iostream>
#include <sstream>
class Logger : public std::ostringstream
{
public:
~Logger()
{
std::cout << this->str() << std::endl;
}
Logger& stream()
{
return *this;
}
};
int main( int argc, char ** argv )
{
// 1.
// Prints an address, e.g. 0x106e89d5c.
Logger() << "foo";
// 2.
// Works as expected.
Logger().stream() << "foo";
// What is the difference between 1. and 2.?
return 0;
}
The operator<< that handles insertion of const char * is a non-member template:
template< class Traits >
basic_ostream<char,Traits>& operator<<(basic_ostream<char,Traits>& os, const char* s);
It takes its stream by non-const (lvalue) reference, which does not bind to temporaries.
In C++98/03, the best viable function is the member operator<<(const void *), which prints an address.
In C++11 and later, the library supplies a special operator<< for rvalue streams:
template< class CharT, class Traits, class T >
basic_ostream< CharT, Traits >& operator<<( basic_ostream<CharT,Traits>&& os,
const T& value );
which does os << value and returns os, essentially performing the output operation on an lvalue stream.
Relevant facts:
Logger() is an rvalue, but Logger().stream() is an lvalue.
The operator<< that takes a pointer and prints its address is a member of ostream&, whereas the operator<< that takes a const char* and prints the string is a free function,
template<class traits>
basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out,
const char* s);
Note that the first argument is a non-const lvalue reference, so it can't bind to an rvalue. Therefore, if the stream is an rvalue, this overload isn't viable. Consequently the const char* is converted to const void* and its address is printed. When you use Logger().stream(), which is an lvalue, this overload wins and the string is printed.
In C++11, a new rvalue stream insertion operator is added:
template <class charT, class traits, class T>
basic_ostream<charT, traits>&
operator<<(basic_ostream<charT, traits>&& os, const T& x);
with the effect os << x. Now this overload wins in Logger() << "foo", and forwards the argument as though the stream were an lvalue. Then the free function previously given is called.
C++11 added this overloaded of non-member operator<<:
template< class CharT, class Traits, class T >
basic_ostream< CharT, Traits >& operator<<( basic_ostream<CharT,Traits>&& os,
const T& value );
Now, the operator you think you're calling in the Logger() case is this one:
template< class Traits >
basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& os,
const char* s );
That works for the Logger().stream() case because that is an lvalue reference, but that doesn't work for Logger() << "foo" case. Logger() cannot bind to an lvalue reference. There, the only viable overload is the member operator<<:
basic_ostream& operator<<( const void* value );
which prints the address.
Im trying to do an override on a simple struct like this:
struct Node {
int data1;
int data2;
ostream& operator<<(ostream &o, const Node &n)
{
o << "(a: " << data1 << ", b: " << data2 << ")";
return o;
}
};
Im getting: error C2804: 'operator <<' too many parameters
So, if i remove the second parameter:
ostream& operator<<(ostream &o)
Then i get: Error: binary '<<' : no operator found which takes a right-hand operand of type 'const Node'
What is coming on here?
operator<< needs two operands. There are two ways to define an operator<< overload function between two types.
As a member function. That's how operator<< overloads between std::basic_ostream and some of the basic types are defined. When you use std:cout << 10;, it gets resolved to the overload operator std::basic_ostream<char>::operator<<(int)
When you define it as member function, the LHS of the operator is an instance of the class. The RHS of the operator is the argument to the function. That's why when you define it as member function, it can only have one argument.
As a free function. That's how operator<< overloads between std::basic_ostream and custom types are defined. These functions must have two arguments. The first argument is the LHS of the operator and the second argument is the RHS of the operator.
For this reasons, you have to define operator<< overload between std::ostream and your class as a free function, with std::ostream& as the first argument type and Node const& as the second argument type.
std::ostream& operator<<(std:ostream& os, Node const& node);
At times like these, I wish the standard library had implemented a function:
template <typename T>
std::ostream& operator<<(std::ostream& os, T const& t)
{
return t.serialize(os);
}
Then, any class could provide the function
std::ostream& serialize(std::ostream& os) const;
and be ready to be used like all the basic types with std::ostream.
std::ostream& operator<<(std::ostream&, ...) needs to be a free function.
Move it outside the class and it will work.
The reason it is so is because defining operator<<(std::ostream&) (or other binary operators) inside the class implies that object is the LHS operand. You would have to write smth crazy like:
Node << std::cout;
In general, how do you declare the index [ ] operator of a class for both read and write accesss?
I tried something like
/**
* Read index operator.
*/
T& operator[](T u);
/**
* Write index operator
*/
const T& operator[](T u);
which gives me the error
../src/Class.h:44:14: error: 'const T& Class::operator[](T)' cannot be overloaded
../src/Class.h:39:8: error: with 'T& Class::operator[](T)'
Your mutable version is fine:
T& operator[](T u);
but the const version should be a const member function as well as returning a const reference:
const T& operator[](T u) const;
^^^^^
This not only distinguishes it from the other overload, but also allows (read-only) access to const instances of your class. In general, overloaded member functions can be distinguished by their parameter types and const/volatile qualifications, but not by their return types.
You simply have one overload that'll be used for both reads and writes:
T& operator[](int);
Having said that, you might also want to have a const overload:
const T& operator[](int) const;
This will provide read-only indexing into const instances of your class.
You get the error, because overloaded functions cannot differ only by return type. But they can differ by const-ness.
/**
* Write index operator.
*/
T& operator[](T u);
/**
* Read index operator
*/
const T& operator[](T u) const;
Note "write" and "read" swapped places.
Also, don't you actually mean the argument of the operator to be some integral type ?
I'm trying to overload the + operator in a forest class, a forest being a collection of trees, and the + operator is supposed to combine two forests into one. I have the following code as my class definition:
template<typename NODETYPE>
class Forest
{
public:
friend Forest& operator+<>(Forest&, Forest&);
friend ostream& operator<<<>(ostream&, const Forest&);
friend istream& operator>><>(istream&, Forest&);
Forest();
Forest( const Forest& otherForest);
~Forest();
void nodes(int&) const;
private:
ForestNode<NODETYPE> *root;
ForestNode<NODETYPE> *getNewNode( const NODETYPE &);
};
The following is my implementation of operator+:
template<typename NODETYPE>
Forest& operator+<>(Forest& f1, Forest& f2)
{
f3 = new Forest();
f3.root = *f1.*root;
f3.root.sibling = *f2.*root;
*f1.root = 0;
*f2.root = 0;
return f3;
}
I get the following error on compile:
|28|error: expected constructor, destructor, or type conversion before '&' token|
line 28 refers to the signature of my operator+ implementation.
I think to correct it i am supposed to add to the return type, giving:
template<typename NODETYPE>
Forest<NODETYPE>& operator+<>(Forest& f1, Forest& f2)
{
f3 = new Forest();
f3.root = *f1.*root;
f3.root.sibling = *f2.*root;
*f1.root = 0;
*f2.root = 0;
return f3;
}
But that gives me the following errors:
|28|error: declaration of 'operator+' as non-function|
|28|error: missing template arguments before '&' token|
|28|error: 'f1' was not declared in this scope|
|28|error: missing template arguments before '&' token|
|28|error: 'f2' was not declared in this scope|
Can anyone help me with this? I'd be very very thankful.
The key to writing operator+ is don't write operator+. Instead, write a copy ctor and operator+=:
template<class NodeType>
struct Forest {
//...
Forest(Forest const &other);
//...
Forest& operator+=(Forest const &other) {
// code here
return *this;
}
//...
};
Now we add operator+:
template<class NodeType>
struct Forest {
//...
friend Forest operator+(Forest a, Forest const &b) {
a += b;
return a;
}
//...
};
And that's it! Copying is usually straight-forward (sometimes by being disallowed) and it may be simpler to think in terms of += than + (you have two objects and mutate one, rather than create a third object out of two). This pattern for op+ works with any similar type, and even for similar operators such as -, *, and /.
Operator overloading can be a good or a bad thing. Good when it leads to simpler looking code. Bad when it leads to writers either overloading with incorrect semantics (yet a solution that compiles) or where the intuitive way to use the operator leads to highly inefficient code.
Note the latter statement can apply to std::string too, which could potentially make large numbers of copies, and which is why the C++03 standard states that a string does not have to be stored internally in a contiguous buffer (in the old days they used copy-on-write references to and could store such references to both strings being concatenated until required. Subsequently it was found to be non-threadsafe and making it so was more costly than simply copying the buffer so now they copy every time and are inefficient again).
(Note that the C++11 standard which recognises threading and atomic issues ensures that the underlying does need to be contiguous and null-terminated to make read operations safe).
The correct signature of operator+ (in the case all are the same type) is as follows:
T operator+( const T&, const T& );
As a member function it would be:
class T
{
// make public if necessary
T operator+( const T& rhs ) const;
};
You can implement operator+ automatically as a template whenever operator += is available with
template<typename T, typename R>
T operator+( const T& lhs, const R& rhs )
{
T copy(lhs);
return copy += rhs;
}
If you want to declare an overloaded operator of your template as a friend, this is the correct way to do it. I will show it with operator<<
// first some forward declarations, assume ostream already declared with #include <iosfwd> minimum
template< typename T > class Forest;
template< typename T > std::ostream & operator<<( std::ostream & os, const Forest<T> & for );
template< typename T> class Forest
{
friend std::ostream& operator<< <>( std::ostream&, const Forest<T> & );
//rest of class Forest
};
template< typename T >
std::ostream & operator<<( std::ostream& os, const Forest<T> & forest )
{
// implement
return os;
}
You would apply a similar technique to any other external function you wish to declare as a friend to your class, i.e.
Forwardly declare your class as a template
Forwardly declare the method as a template function
Make the function a friend using <> before the opening parentheses denoting the parameters
Implement the function after your class.
You have to provide a template arguments for all Forest parameters.
template<typename NODETYPE>
Forest<NODETYPE> operator+(Forest<NODETYPE>& f1, Forest<NODETYPE>& f2)
Also, consider making the arguments const references to make sure you do not manipulate them.
There are several questions on stackoverflow regarding friend function templates. The C++ FAQ also has a page on them that explains some basics.
You can define an operator+ template as follows:
template< class NodeType >
Forest<NodeType> operator+( Forest<NodeType> const& f1, Forest<NodeType> const& f2)
{
// Implementation.
}
Cheers & hth.,
As in the question, if I define a string operator in my class:
class Literal {
operator string const () {
return toStr ();
};
string toStr () const;
};
and then I use it:
Literal l1 ("fa-2bd2bc3e0");
cout << (string)l1 << " Declared" << endl;
with an explicit cast everything goes right, but if I remove the (string) the compiler says that it needs a cast operator declared in std::string. Shouldn't it cast my type automatically?
SOLVED: I'm overloading operator<< (ostream& os, const Literal& l).
No.. std::string would have to have a constructor that took Literal as an argument.
What you could do is overload operator << for your Literal class and have it cast and insert into the stream in there.
ostream &operator <<(std::ostream &stream, const Literal &rhs)
{
stream << (string) rhs;
return stream;
}
Short answer: Keep using a cast or toStr(), or write your own operator<< function. (I would prefer l1.toStr() to (string)l1.)
Long answer:
This might work if the Standard Library had a function
std::ostream& operator<<( std::ostream&, std::string const& );
Which it almost does, but not technically. Both ostream and string are really typedefs of template instantiations. And there's a template function for inserting one into the other.
// This is somewhat simplified. For the real definitions, see the Standard
// and/or your complying implementation's headers.
namespace std {
typedef basic_string<char> string;
typedef basic_ostream<char> ostream;
template <typename CharT>
basic_ostream<CharT>& operator<<(
basic_ostream<CharT>&,
basic_string<CharT> const&);
}
So when you use cout << str where the type of str is std::string, it can figure out to use that template function, with CharT = char.
But C++ doesn't allow you to have the compiler figure out both an implicit type conversion (Literal to string) and deduce template function template parameters (CharT = char) on the same call.