Here is another question. But my question is not same as it. I want a stack can be handled like a one pass range, not to handle it like its' underlying container. The stack in my question only support pop and push , and once you read one element from the stack, it will be removed.
I have a stack that only support pop and push, here is an example. I can handle the elements in the stack one by one, just like a range. So I want it to be a range (support std::ranges::range). How can I do it elegantly?
#include <memory>
#include <iostream>
#include <stack>
template <typename T>
struct my_stack : private std::stack<T> {
using base = std::stack<T>;
using base::push;
auto pop() {
auto ret = std::move(base::top());
base::pop();
return std::move(ret);
}
bool empty() {
return base::size() == 0;
}
};
int main() {
my_stack<int> s;
s.push(1);
s.push(3);
s.push(5);
s.push(7);
while(!s.empty()) {
std::cout << s.pop() << std::endl;
}
}
Here is a try, it works but I don't like it much.
#include <memory>
#include <iostream>
#include <stack>
#include <optional>
template <typename T>
struct my_stack : private std::stack<T> {
using base = std::stack<T>;
using base::push;
auto pop() {
auto ret = std::move(base::top());
base::pop();
return std::move(ret);
}
bool empty() {
return base::size() == 0;
}
std::optional<T> optional_pop() {
if(empty()) return {};
return std::move(pop());
}
struct iterator {
std::optional<T> _op_val;
my_stack *_p_stack;
T operator*() {
return std::move(_op_val.value());
}
iterator& operator++() {
_op_val = _p_stack->optional_pop();
return *this;
}
auto operator<=>(const iterator&) const = default;
};
iterator end() {
return iterator{{}, this};
}
iterator begin() {
return iterator{optional_pop(), this};
}
};
int main() {
my_stack<int> s;
for(auto val : s) {
std::cout << val << std::endl;
}
s.push(1);
s.push(3);
s.push(5);
s.push(7);
for(auto val : s) {
std::cout << val << std::endl;
}
}