Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Input from stream to enum type

Tags:

c++

enums

istream

How to input from stream to enum type?

I can do it so

unsigned int sex = 0;
stream >> sex;
student.m_bio.sex = static_cast<Sex>(sex);

Otherwise?

like image 809
Dmitry Zhlobo Avatar asked Apr 12 '11 10:04

Dmitry Zhlobo


Video Answer


3 Answers

inline std::istream & operator>>(std::istream & str, Sex & v) {
  unsigned int sex = 0;
  if (str >> sex)
    v = static_cast<Sex>(sex);
  return str;
}

If you want to ensure that the value is valid, you can do something like this:

enum Sex {
    Male,
    Female,
    Sex_COUNT
};

inline std::istream & operator>>(std::istream & str, Sex & v) {
  unsigned int sex = 0;
  if (!(str >> sex))
    return str;
  if (sex >= Sex_COUNT) {
    str.setstate(str.rdstate() | std::ios::failbit);
    return str;
  }
  v = static_cast<Sex>(sex);
  return str;
}
like image 179
Erik Avatar answered Oct 18 '22 15:10

Erik


This question was asked in a more general form over here: How to read enums from a std::istream in a generic fashion. The OP almost had a working solution as it was; he just had some trouble with const, and a few unnecessary angle-brackets. Here's the working solution fleshed out:

#include <iostream>
#include <type_traits>

enum enSide { eLeft, eRight };
enum enType { eConUndefined, eConRoom };

template<typename Enum>
class EnumReader
{
    Enum& e_;

    friend std::istream& operator>>(std::istream& in, const EnumReader& val) {
      typename std::underlying_type<Enum>::type asInt;
      if (in >> asInt) val.e_ = static_cast<Enum>(asInt);
      return in;
    }
  public:
    EnumReader(Enum& e) : e_(e) {}
};

template<typename Enum>
EnumReader<Enum> read_enum(Enum& e)
{
    return EnumReader<Enum>(e);
}

class MyClass {
    enSide mSide;
    enType mType;
    int mTargetId;
  public:
    friend std::istream& operator>>(std::istream& in, MyClass& val) {
        in >> read_enum(val.mSide) >> read_enum(val.mType) >> val.mTargetId;
        return in;
    }
};

The read_enum function template serves the same purpose here as std::make_pair or std::make_shared in the standard library: it lets us dispense with the angle brackets. You could equally well write in >> EnumReader<enSide>(val.mSide) >> EnumReader<enType>(val.mType), but that's more typing (pun intended).

A few vendors' standard libraries are allegedly still missing std::underlying_type from their <type_traits> headers. If you have one of these incomplete libraries, you can use one of the workarounds listed at How to know underlying type of class enum?.

like image 22
Quuxplusone Avatar answered Oct 18 '22 13:10

Quuxplusone


This is not pretty but should do it

stream >>  reinterpret_cast<std::underlying_type<Sex>::type &>(student.m_bio.sex);

Cheers, CC

like image 33
Catriel Avatar answered Oct 18 '22 14:10

Catriel