overloaded << issue

I have overloaded the operator << but I am getting the error binary '[': no operator found which takes a left-hand operand of type 'const array<T>' (or there is no acceptable conversion), but I dont understand why, this is the way ive overloaded before and it worked all the other times

Overloaded function at bottom of the stack class.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
  #pragma once
#include <iostream>
#include "array.h"

template <typename T>
class stack
{
private:
	int Top = -1;
	int count = 0;
	array<T> Array;

public:
	explicit stack(int size) :  Array(size) { }

	void Push(const T &value)
	{
		Top++;
		Array[Top] = value;	
		count++;
	}

	T Pop()
	{
		count--;
		T element = Array[Top];
		Top--;
		return element;		
	}

	bool isEmpty() const
	{
		return (count == 0);
	}

	int returnSize() const
	{
		return count;
	}

	friend std::ostream& operator << (std::ostream& stream, const stack<T> & obj)
	{
		if (obj.isEmpty())
		{
			stream << "Stack is empty\n";
		}
		else
		{
			for (int i = obj.Top; i>= 0; i--)
			{
				stream << obj.Array[i] << " ";
			}			
		}
		return stream;		
	}


};


array class if needed

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#pragma once
template <typename T>
class array
{
private:
	T* ptr = nullptr;
	int size;

public:
	array(int Size) : size(Size)
	{
		ptr = new T[size];
	}

	~array()
	{
		delete ptr;
		ptr = nullptr;
	}

	int arraySize()
	{
		return size;
	}
	//Access to index
	T& operator[] (int index)
	{
		return index;
	}
	
	friend std::ostream& operator << (std::ostream& stream, const array<T>& obj)
	{
		stream << "[";
		for (int i = 0; i < obj.arraySize(); i++)
		{
			stream << obj[i] << ",";
		}
		stream << " ]";
		return stream;
	}
	
};
The problem is with your operator[] definition in array. Try:

1
2
3
4
5
6
7
8
9
	T& operator[] (int index)
	{
		return ptr[index];
	}

	const T& operator[] (int index) const
	{
		return ptr[index];
	}

You're also missing const on arraySize().

1
2
3
4
	int arraySize() const
	{
		return size;
	}

You shouldn't need both count and Top. They're virtually the same.
And the delete for array should be delete[].
Also, your push and pop should check for overflow or underflow.
Last edited on
Consider:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#include <iostream>

template <typename T>
class array
{
private:
	T* ptr {};
	size_t size {};

public:
	array() {}
	array(size_t Size) : size(Size), ptr(new T[Size]) {}
	~array() { delete [] ptr; }

	size_t arraySize() const { return size; }
	T& operator[] (size_t index) { return ptr[index]; }
	const T& operator[] (size_t index) const { return ptr[index]; }

	friend std::ostream& operator << (std::ostream& stream, const array<T>& obj)
	{
		stream << "[ ";

		for (size_t i = 0; i < obj.arraySize(); ++i) {
			if (i != 0) stream << ", ";
			stream << obj[i];
		}

		return stream << " ]";
	}
};

template <typename T>
class stack
{
private:
	size_t count {};
	array<T> Array;

public:
	stack() {}
	explicit stack(size_t size) : Array(size) { }

	void Push(const T& value) { Array[count++] = value; }

	T Pop() { return Array[--count]; }

	bool isEmpty() const { return count == 0; }

	int returnSize() const { return count; }

	friend std::ostream& operator << (std::ostream& stream, const stack<T>& obj)
	{
		if (obj.isEmpty())
			return stream << "Stack is empty\n";

		for (size_t i = obj.count; i > 0; --i)
			stream << obj.Array[i - 1] << " ";

		return stream;
	}
};

int main()
{
	stack<int> s(5);

	s.Push(1);
	s.Push(2);
	std::cout << s << "\n\n";

	s.Pop();
	std::cout << s << '\n';
}



2 1

1

@seeplus, consider:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
// array.h //////////////////////////////////////////

// pragma once
#include <ostream>
#include <algorithm>
#include <utility>

template <typename T>
class Array
{
private:
    size_t m_size;
    T*     m_data;
public:
    Array(size_t size) : m_size(size), m_data(new T[size]) { }

    Array(const Array& other)
    {
        m_size = other.m_size;
        m_data = new T(other.m_size);
        std::copy(other.m_data, other.m_data + other.m_size, m_data);
    }

    Array(Array&& other)
    {
        m_size = other.m_size;
        m_data = other.m_data;
        other.m_size = 0;
        other.m_data = nullptr;
    }

    Array& operator=(const Array& other)
    {
        if (this = &other) return *this;
        if (size != other.size)
        {
            delete[] m_data;
            m_data = nullptr;
            m_size = 0; // preserve invariants (in case next line throws(
            m_data = new T[other.m_size];
            m_size = other.m_size;
        }
        std::copy(other.m_data, other.m_data + other.size, m_data);
        return *this;
    }

    Array& operator=(Array&& other)
    {
        if (this = &other) return *this;
        delete[] m_data;
        m_data = std::exchange(other.m_data, nullptr);
        m_size = std::exchange(other.size, 0);
        return *this;
    }

    ~Array() { delete[] m_data; }

    size_t size() const { return m_size; }

    T& operator[](size_t index) { return m_data[index]; }

    const T& operator[](size_t index) const { return m_data[index]; }
    
    friend std::ostream& operator<<(std::ostream& out, const Array<T>& obj)
    {
        out << '[';
        for (size_t i = 0; i < obj.m_size; ++i)
            out << (i ? "," : "") << obj.m_data[i];
        return out << ']';
    }
};


// stack.h //////////////////////////////////////////

// pragma once
#include <ostream>
#include <stdexcept>
#include <utility>
//#include "array.h"

template <typename T>
class Stack
{
private:
    size_t   m_top   = 0;
    Array<T> m_array;

public:
    struct StackError : public std::runtime_error
    {
        StackError(const std::string& what) : runtime_error(what) { }
    };

    explicit Stack(size_t size) : m_array(size) { }

    Stack(const Stack& s) { m_top = s.m_top; m_array = s.m_array; }

    Stack(Stack&& s)
    {
        m_top = s.m_top;
        s.m_top = 0;
        m_array = std::move(s.m_array);
    }

    Stack& operator=(Stack other)
    {
        std::swap(m_top, other.m_top);
        std::swap(m_array, other.m_array);
        return *this;
    }

    void push(const T& value)
    {
        if (m_top == m_array.size()) throw StackError("overflow");
        m_array[m_top++] = value;
    }

    T pop()
    {
        if (empty()) throw StackError("underflow");
        return m_array[--m_top];        
    }

    bool empty() const { return m_top == 0; }

    size_t size() const { return m_top; }

    friend std::ostream& operator<<(std::ostream& out, const Stack<T>& obj)
    {
        if (obj.empty())
            out << "<empty>";
        else
            for (size_t i = obj.m_top; i-- > 0; )
                out << obj.m_array[i] << ' ';
        return out;
    }
};


// main.cpp ////////////////////////////////////////////

#include <iostream>

int main()
{
    using std::cout;

    Stack<int> s(10);

    cout << "Pushing:\n";
    for (int i = 0; i < 9; ++i)
    {
        cout << i << ' ' << std::flush;
        s.push(i);
    }

    cout << "\nPopping:\n";
    for (int i = 0; i < 6; ++i) cout << s.pop() << ' ' << std::flush;

    cout << "\nPrinting:\n";
    cout << s << '\n';
}

@dutch. OK. I just cleaned up the OP code and didn't provide the extra member functions required for them to be fully functioning classes. I probably should have. My bad.

PS Shouldn't L20 be

 
m_data = new T[other.m_size];


L34
 
if (this == &other) return *this;


L49
 
if (this == &other) return *this;


giving:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#include <iostream>
#include <algorithm>
#include <utility>
#include <stdexcept>

template <typename T>
class Array
{
private:
	size_t m_size {};
	T* m_data {};
public:
	Array() {}
	Array(size_t size) : m_size(size), m_data(new T[size]) { }

	Array(const Array& other) : m_size(other.m_size), m_data(new T[other.m_size])
	{
		std::copy_n(other.m_data, m_size, m_data);
	}

        Array(Array&& other) : m_size(other.m_size), m_data(std::exchange(other.m_data, nullptr)) {}

	Array& operator=(const Array& other)
	{
		if (this != &other) {
			if (size != other.size) {
				delete[] m_data;
				m_data = nullptr;
				m_size = 0; // preserve invariants (in case next line throws(
				m_data = new T[other.m_size];
				m_size = other.m_size;
			}

			std::copy_n(other.m_data, other.size, m_data);
		}
		return *this;
	}

	Array& operator=(Array&& other)
	{
		if (this != &other) {
			delete[] m_data;
			m_data = std::exchange(other.m_data, nullptr);
			m_size = std::exchange(other.size, 0);
		}
		return *this;
	}

	~Array() { delete[] m_data; }

	size_t size() const { return m_size; }

	T& operator[](size_t index) { return m_data[index]; }

	const T& operator[](size_t index) const { return m_data[index]; }

	friend std::ostream& operator<<(std::ostream& out, const Array<T>& obj)
	{
		out << '[';
		for (size_t i = 0; i < obj.m_size; ++i)
			out << (i ? "," : "") << obj.m_data[i];

		return out << ']';
	}
};

template <typename T>
class Stack
{
private:
	size_t   m_top {};
	Array<T> m_array {};

public:
	struct StackError : public std::runtime_error
	{
		StackError(const std::string& what) : runtime_error(what) { }
	};

	Stack() {}
	explicit Stack(size_t size) : m_array(size) { }

	Stack(const Stack& s) : m_top(s.m_top), m_array(s.m_array) {}

	Stack(Stack&& s) : m_top(s.m_top), m_array(std::move(s.m_array)) {}

	Stack& operator=(Stack other)
	{
		std::swap(m_top, other.m_top);
		std::swap(m_array, other.m_array);
		return *this;
	}

	void push(const T& value)
	{
		if (m_top == m_array.size())
			throw StackError("overflow");

		m_array[m_top++] = value;
	}

	T pop()
	{
		if (empty())
			throw StackError("underflow");

		return m_array[--m_top];
	}

	bool empty() const { return m_top == 0; }

	size_t size() const { return m_top; }

	friend std::ostream& operator<<(std::ostream& out, const Stack<T>& obj)
	{
		if (obj.empty())
			return out << "<empty>";

		for (size_t i = obj.m_top; i-- > 0; )
			out << obj.m_array[i] << ' ';

		return out;
	}
};

int main()
{
	using std::cout;

	Stack<int> s(10);

	cout << "Pushing:\n";
	for (int i = 0; i < 9; ++i)
	{
		cout << i << ' ';
		s.push(i);
	}

	cout << "\nPopping:\n";
	for (int i = 0; i < 6; ++i)
		cout << s.pop() << ' ';


	cout << "\nCopying to s1";
	auto s1 {s};

	cout << "\nPrinting:\n";
	cout << s1 << '\n';
}



Pushing:
0 1 2 3 4 5 6 7 8
Popping:
8 7 6 5 4 3
Copying to s1
Printing:
2 1 0

Last edited on
and using swap and noexcept:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#include <iostream>
#include <algorithm>
#include <utility>
#include <stdexcept>

template <typename T>
class Array
{
private:
	size_t m_size {};
	T* m_data {};
public:
	Array() noexcept {}
	Array(size_t size) : m_size(size), m_data(new T[size]) {}

	Array(const Array& other) : m_size(other.m_size), m_data(new T[other.m_size])
	{
		std::copy_n(other.m_data, m_size, m_data);
	}

	Array(Array&& other) noexcept : m_size(other.m_size), m_data(std::exchange(other.m_data, nullptr)) {}

	void swap(Array& other) noexcept
	{
		std::swap(m_size, other.m_size);
		std::swap(m_data, other.m_data);
	}

	Array& operator=(const Array& other)
	{
		if (m_size >= other.m_size) {
			m_size = other.m_size;
			std::copy_n(other.m_data, m_size, m_data);
		} else {
			Array tmp(other);

			swap(tmp);
		}
		return *this;
	}

	Array& operator=(Array&& other) noexcept
	{
		swap(other);
		return *this;
	}

	~Array() { delete[] m_data; }

	size_t size() const noexcept { return m_size; }

	T& operator[](size_t index) { return m_data[index]; }

	const T& operator[](size_t index) const { return m_data[index]; }

	friend std::ostream& operator<<(std::ostream& out, const Array<T>& obj)
	{
		out << '[';
		for (size_t i = 0; i < obj.m_size; ++i)
			out << (i ? "," : "") << obj.m_data[i];

		return out << ']';
	}
};

template <typename T>
class Stack
{
private:
	size_t   m_top {};
	Array<T> m_array {};

public:
	struct StackError : public std::runtime_error
	{
		StackError(const std::string& what) : runtime_error(what) {}
	};

	Stack() noexcept {}
	explicit Stack(size_t size) : m_array(size) { }

	Stack(const Stack& s) : m_top(s.m_top), m_array(s.m_array) {}

	Stack(Stack&& s) noexcept : m_top(s.m_top), m_array(std::move(s.m_array)) {}

	void swap(Stack& other) noexcept
	{
		std::swap(m_top, other.m_top);
		std::swap(m_array, other.m_array);
	}

	Stack& operator=(const Stack& other)
	{
		if (m_top >= other.m_top) {
			m_array = other.m_array;
			m_top = other.m_top;
		} else {
			Stack tmp(other);

			swap(tmp);
		}
		return *this;
	}

	Stack& operator=(Stack&& other) noexcept
	{
		swap(other);
		return *this;
	}

	void push(const T& value)
	{
		if (m_top == m_array.size())
			throw StackError("overflow");

		m_array[m_top++] = value;
	}

	T pop()
	{
		if (empty())
			throw StackError("underflow");

		return m_array[--m_top];
	}

	bool empty() const noexcept { return m_top == 0; }

	size_t size() const noexcept { return m_top; }

	friend std::ostream& operator<<(std::ostream& out, const Stack<T>& obj)
	{
		if (obj.empty())
			return out << "<empty>";

		for (size_t i = obj.m_top; i-- > 0; )
			out << obj.m_array[i] << ' ';

		return out;
	}
};

int main()
{
	using std::cout;

	Stack<int> s(10);

	cout << "Pushing:\n";
	for (int i = 0; i < 9; ++i)
	{
		cout << i << ' ';
		s.push(i);
	}

	auto s2 {s};

	cout << "\nPopping:\n";
	for (int i = 0; i < 6; ++i)
		cout << s.pop() << ' ';

	cout << "\nCopying to s1";
	auto s1 {s};

	cout << "\nPrinting:\n";
	cout << s1 << '\n';

	s1 = s2;
	cout << s1 << '\n';
}

Last edited on
and to demonstrate exceptions:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
int main()
{
	using std::cout;

	Stack<int> s(5);

	cout << "Pushing:\n";
	try {
		for (int i = 0; i < 9; ++i)
		{
			cout << i << ' ';
			s.push(i);
		}
	}
	catch (const Stack<int>::StackError& se)
	{
		cout << "\nStack error - " << se.what() << '\n';
	}

	auto s2 {s};

	cout << "\nPopping:\n";

	try {
		for (int i = 0; i < 6; ++i)
			cout << s.pop() << ' ';
	}
	catch (const Stack<int>::StackError& se)
	{
		cout << "\nStack error - " << se.what() << '\n';
	}

	cout << "\nCopying to s1";
	auto s1 {s};

	cout << "\nPrinting:\n";
	cout << s1 << '\n';

	s1 = s2;
	cout << s1 << '\n';
}



Pushing:
0 1 2 3 4 5
Stack error - overflow

Popping:
4 3 2 1 0
Stack error - underflow

Copying to s1
Printing:
<empty>
4 3 2 1 0

Topic archived. No new replies allowed.