Anna P.
Anna P.

Reputation: 33

Overridden << operator not recognized

I'm trying to override the << operator but it seems that the compiler doesn't recognize my implementation and instead tries to interpret it as a bit shift. I've already tried to play around with the parameter types (const T&, T&, T, const T) to no avail.

#pragma once

template<typename T> class AbstractStack
{
    public:
        virtual bool Push(const T &) = 0;
}

template <typename T> class ArrayStack : public AbstractStack <T>
{
    public:
        bool Push(const T&) {
            ....
        }
}

template <typename T> bool operator<<(const AbstractStack<T>* &, const T&) {
    return stack->Push(item);
}


int main() {
    AbstractStack<int> *stack = new ArrayStack<int>(5);
    int a = 2;
    stack << a; // <<-- compiler error
    return 0;
}

The error reported is:

Error (active)      expression must have integral or unscoped enum type Lab10   
Error   C2296   '<<': illegal, left operand has type 'AbstractStack<int> *' 

If I define the same operator acting on the class as a value, it just works...

Upvotes: 3

Views: 399

Answers (2)

Niall
Niall

Reputation: 30606

When overloading operators, at least one of the arguments must be a class or an enum type - basically this allows/limits you to overloading custom types (user defined types).

From the cppreference;

When an operator appears in an expression, and at least one of its operands has a class type or an enumeration type, then overload resolution is used to determine the user-defined function to be called among all the functions whose signatures match the following...

This makes sense in that it disallows you from overloading the built in types; in this case, the pointer and integer you have as arguments.

As you already remarked in the question, the solution is taking your first argument by reference;

template <typename T>
bool operator<<(AbstractStack<T> &, const T&)
{ //...

Given the abstract base class you are looking to use, you could investigate the use of std::shared_ptr to help manage the resources and make the use of a "pointer" in the overloaded operator (albeit it will be a smart pointer);

template <typename T>
bool operator<<(std::shared_ptr<AbstractStack<T>>&, const T&)
{
  return stack->Push(item);
}

int main() {
  std::shared_ptr<AbstractStack<int>> stack = std::make_shared<ArrayStack<int>>(5);
  int a = 2;
  stack << a;
  return 0;
}

Upvotes: 3

Pete Becker
Pete Becker

Reputation: 76245

As others have said, overloading any builtin operator requires an object of a user-defined type; a pointer won't work. And the solution is to use an object instead of a pointer:

template <typename T> bool operator<<(AbstractStack<T>&, const T&) {
    return stack.Push(item);
}

and then call it with an object. There's no good reason in the code you've shown to allocate from the free-store; just create an auto object:

int main() {
    ArrayStack<int> stack(5);
    int a = 2;
    stack << a;
    return 0;
}

Upvotes: 2

Related Questions