Se però vuoi mantenere l'informazione del tipo iniziale puoi usare il metodo "classico" C per gestire queste situazioni: struct+union+enum, condendola con un goccio di C++ per renderla più comoda:
codice:
#include <stack>
#include <iostream>
#include <stdexcept>
using std::cout;
// L'elemento da mettere nella lista
struct Elem
{
// Una union condivide la memoria tra due elementi
// Di fatto significa che puoi leggere solo dall'ultimo che hai scritto se vuoi avere risultati sensati
// Qui memorizziamo i dati
union
{
char c;
int i;
} u;
// Qui invece memorizziamo il tipo effettivamente registrato in u
enum
{
elemChar,
elemInt
} type;
// Costruttori per rendere comodo l'uso della struct
Elem(char c) : type(elemChar)
{
u.c=c;
}
Elem(int i) : type(elemInt)
{
u.i=i;
}
// Operatori di conversione implicita ai tipi desiderati
operator int() const
{
if(type!=elemInt)
throw std::logic_error("Questo elemento non contiene un int.");
return u.i;
}
operator char() const
{
if(type!=elemChar)
throw std::logic_error("Questo elemento non contiene un char.");
return u.i;
}
};
// Operatore di scrittura su stream per comodità
std::ostream & operator<<(std::ostream & os, const Elem & right)
{
if(right.type==Elem::elemInt)
os<<(int)right;
else
os<<(char)right;
}
int main()
{
std::stack<Elem> stack;
stack.push('a');
stack.push(1);
int i = stack.top(); // memorizza 1 in i (estrae l'int grazie al cast implicito - per sicurezza può essere meglio usare un cast esplicito in casi ambigui)
cout<<"Ho estratto: "<<i<<"\n";
stack.pop();
cout<<"Ora scrivo l'altro elemento direttamente sullo stream: "<<stack.top()<<"\n"; // stampa a grazie all'operatore in overload
try
{
// Prova a prendere un char e un int da un elemento che in realtà contiene un char
char c = stack.top();
cout<<"char estratto senza problemi!\n";
int i = stack.top();
cout<<"int estratto senza problemi!\n";
}
catch(std::exception & ex)
{
cout<<"Catturata eccezione: "<<ex.what()<<"\n";
}
return 0;
}
(lo vedi in azione direttamente qui)
L'alternativa, per non stare a reinventare la ruota ogni volta, può essere usare boost::variant (che va bene per casi come questo in cui i tipi da memorizzare sono determinati in maniera fissa)
codice:
#include <stack>
#include <iostream>
#include <boost/variant.hpp>
using std::cout;
int main()
{
std::stack<boost::variant<char, int> > stack;
stack.push('a');
stack.push(1);
int i = boost::get<int>(stack.top()); // memorizza 1 in i
cout<<"Ho estratto: "<<i<<"\n";
stack.pop();
cout<<"Ora scrivo l'altro elemento direttamente sullo stream: "<<stack.top()<<"\n"; // stampa a grazie all'operatore in overload
try
{
// Prova a prendere un char e un int da un elemento che in realtà contiene un char
char c = boost::get<char>(stack.top());
cout<<"char estratto senza problemi!\n";
int i = boost::get<int>(stack.top());
cout<<"int estratto senza problemi!\n";
}
catch(std::exception & ex)
{
cout<<"Catturata eccezione: "<<ex.what()<<"\n";
}
return 0;
}
(link)
Vale la pena di sapere che esiste anche boost::any se devi poter memorizzare qualunque valore.