You can write streaming operators for your enumeration type, after which they can be used naturally with <<
and >>
:
#include <iostream>
#include <string>
#include <sstream>
enum class SchoolType {
Primary = 1,
Secondary = 2
};
std::ostream& operator<<(std::ostream& os, SchoolType s)
{
return os << (s == SchoolType::Primary ? "Primary" :
s == SchoolType::Secondary ? "Secondary" :
throw std::runtime_error("invalid SchoolType output"));
}
std::istream& operator>>(std::istream& is, SchoolType& s)
{
std::string word;
if (is >> word)
{
if (word == "Primary") { s = SchoolType::Primary; return is; }
if (word == "Secondary") { s = SchoolType::Secondary; return is; }
is.setstate(std::ios::failbit);
}
return is;
}
int main()
{
std::cout << SchoolType::Primary << ' ' << SchoolType::Secondary << '\n';
std::istringstream iss("Primary Secondary Fail");
SchoolType a, b;
iss >> a >> b;
std::cout << a << ' ' << b << " good:" << iss.good() << '\n';
iss >> a;
std::cout << "good:" << iss.good() << '\n';
}
See the code run here.
CAUTION: The simple streaming to std::string
then checking for an enumeration identifier requires a little care in use: the identifier must be delimited by whitespace (e.g. space, tab, newline) or End-Of-File; trailing characters like punctuation or brackets/braces/parentheses will be sucked into the string, then the comparison will fail and throw.
A more complex but robust version is available here, using a supporting class Identifier
for character-by-character input and unget()
at the first character not legal in an identifier. With this, in operator>>(std::istream& is, SchoolType& s)
just replace std::string word;
with Identifier word;
.
struct Identifier : std::string { };
std::istream& operator>>(std::istream& is, Identifier& idn)
{
idn.clear();
char c;
if (is >> c)
{
if (!std::isalnum(c))
is.setstate(std::ios::failbit);
else
{
idn += c;
while (is.get(c))
if (std::isalnum(c) || c == '_')
idn += c;
else
{
is.unget();
break;
}
// hit EOF, is.get(c) will have left fail condition set
is.clear(); // doesn't matter that we also clear EOF
}
}
return is;
}
(In practice, I prefer to write to-string and from-string functions, then write the streaming operators using those: it's sometimes more convenient e.g. if you quickly want a string representation without creating streams).