04.11.2021 13:45 Frederick Gotham kirjutas:
> I'm writing a class called "MultiStack". It is a stack container in
> which the elements can be of different types, for example you can push
> an 'int' onto the stack, and then push a 'std::string' onto the stack.
>
As others have commented, the abstraction is in the wrong place here.
The stack should not concern itself about such details about its
elements. Instead, one adds an abstraction layer like std::variant or
std::any, and keeps the stack implementation unchanged. Otherwise you
will soon find yourself reimplementing also vector, list, map, etc.
A major point about C++ is that adding such abstraction layers does not
cause any extra performance penalties.
> So now the only member function left to implement is "top". At first
> glance, you might think that the way to implement "top" would be to have
> multiple overloads of the member function "top", but C++ doesn't allow
> function overloads that only differ by return type. The following is
> disallowed:
>
> class MultiStack {
> public:
> int top(void) { /* implementation */ }
> float top(void) { /* implementation */ }
> std::string top(void) { /* implementation */ }
> };
Sure, but you can have template member functions:
class MultiStack {
public:
template<typename T> T top();
template<typename T> bool top_is();
};
For using this I also added a type check function top_is(). A basic
usage example:
MultiStack stack = ...;
if (stack.top_is<int>()) {
int x = stack.top<int>();
} else if (stack.top_is<float>()) {
float f = stack.top<float>();
} else if (stack.top_is<std::string>()) {
std::string s = stack.top<std::string>();
}
This usage would be about at least hundreds of times faster than abusing
the exception throw/catch mechanism.
Of course, this would still be abstraction in wrong place, and this all
would be resolved better by using std::stack<std::any> or similar.