How to read enums from a std::istream in a generic fashion [duplicate]

时光总嘲笑我的痴心妄想 提交于 2020-01-03 19:51:20

问题


Possible Duplicate:
Input from stream to enum type

I have several classes with different enums as class members and I want to read the classes from a stream.

The following code shows an exemplary class:

  enum enSide{
    eLeft,
    eRight
  };

  enum enType{
    eConUndefined,
    eConRoom    
  };

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

      MyClass(){}

    private:
      enSide mSide;
      enType mType;
      int mTargetId; 
  };

Unfortunately this does not work since direct reading into an enum Value is not possible (no template for >>).

Thus I created a helper class:

template<class ENUM>
class ScanTo{
  public:
    friend std::istream& operator>>(std::istream& in, ScanTo<ENUM>& eval) {
      unsigned int val;
      in >> val;
      eval.mrEnum = static_cast<ENUM>(val);
      return in;      
    }

    ScanTo(ENUM& eRef):mrEnum(eRef){}

  private:
    ENUM& mrEnum;    
};

Now I can write the code for reading MyClass as follows:

friend std::istream& operator>>(std::istream& in, MyClass& val) {
  ScanTo<enSide> scanside(val.mSide);
  ScanTo<enType> scantype(val.mType);
  in >> scanside >> scantype >> val.mTargetId;        
  return in;      
}

This is already not far from what I wanted but still needs two indirections over the helper class, which cannot be written as temporarys:

friend std::istream& operator>>(std::istream& in, MyClass& val) {
 in >>  ScanTo<enSide>(val.mSide)>> ScanTo<enType>(val.mType) >> val.mTargetId;        
 return in;      
}

does not compile (gcc 4.43), because a non const reference to a temporary is forbidden as pointed out in the comments.

So here comes the question:

Can this be done easier without resorting to some temporaries and templates as done above?


回答1:


I think you may write a helper function template:

template <class T>
std::istream& operator >>(std::istream& is, T& t)
{
    int i;
    is >> i;
    t = (T)i;
    return is;
}

which makes

in >> val.mSide >> val.mType >> val.mTargetId;

possible.




回答2:


The best option for you is to define your data members as int, and use type safe accessors to set and retrieve them.

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

    MyClass(){}

    enSide side () const { return static_cast<enSide>(mSide); }
    void side (enSide v) { mSide = v; }

    enType type () const { return static_cast<enType>(mType); }
    void type (enType v) { mType = v; }

    int targetId () const { return mTargetId; }
    void targetId (int v) { mTargetId = v; }

  private:
    int mSide;
    int mType;
    int mTargetId; 
};

This avoids the temporaries as you desired.



来源:https://stackoverflow.com/questions/11177580/how-to-read-enums-from-a-stdistream-in-a-generic-fashion

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!