I’m making a simple class that uses operator<<. It will store two parallel arrays of data, each with a different (but already-known) datatype. The idea is that the final interface will look something like this:
MyInstance << "First text" << 1 << "Second text" << 2 << "Third text" << 3;
Which would make the arrays look something like this:
StringArray: | "First text" | "Second text" | "Third text" |
IntArray: | 1 | 2 | 3 |
I can handle the logic of checking the input to make sure everything matches up, but I’m confused with the technical details of operator<<.
The tutorials I checked say to overload it as a friend function with an std::ostream& return type, but my class has nothing to do with streams. I tried using void as the return type but got compilation errors. Eventually I ended up with returning a reference to the class, but I’m not sure why that works.
Here is my code so far:
class MyClass
{
public:
MyClass& operator<<(std::string StringData)
{
std::cout << "In string operator<< with " << StringData << "." << std::endl;
return *this; // Why am I returning a reference to the class...?
}
MyClass& operator<<(int IntData)
{
std::cout << "In int operator<< with " << IntData << "." << std::endl;
return *this;
}
};
int main()
{
MyClass MyInstance;
MyInstance << "First text" << 1 << "Second text" << 2 << "Third text" << 3;
return 0;
}
Additionally, the user of my class can do something like this, which is unwanted:
MyInstance << "First text" << 1 << 2 << "Second text" << "Third text" << 3;
What can I do to enforce the alternating nature of the input?
The reason
ostreamoperators return a reference to theostream, and the reason it somewhat helped your case to return a reference toMyClassis that an expression likeA << B << Cis always interpreted like(A << B) << C. That is, whatever the first overloaded operator returns becomes the left-hand side of the next operator call.Now, if you want an expression like
MyInstance << "First text" << 1 << 2to produce a compiler error, you need to make sure that the type returned after the first two<<operators is a type that cannot be called with another int. I think something like this might do what you want (thanks to @Pete Kirkham for a good improvement idea):Those would be the only two overloaded
operator<<functions you define related toMyClass. This way, every time you call anoperator<<, the compiler switches the return type fromMyClass&toMyClass_ExpectIntor vice-versa, and passing the “wrong” sort of data tooperator<<is never allowed.