C++ 如何以通用方式从std::istream读取枚举

C++ 如何以通用方式从std::istream读取枚举,c++,templates,enums,iostream,C++,Templates,Enums,Iostream,可能重复: 我有几个类作为类成员使用不同的枚举,我想从流中读取这些类 以下代码显示了一个示例类: enum enSide{ eLeft, eRight }; enum enType{ eConUndefined, eConRoom }; class MyClass{ public: friend std::istream& operator>>(std::istream& in, M

可能重复:

我有几个类作为类成员使用不同的枚举,我想从流中读取这些类

以下代码显示了一个示例类:

  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; 
  };
不幸的是,这不起作用,因为无法直接读取
枚举值(没有>>的模板)。

因此,我创建了一个助手类:

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;    
};
这已经离我想要的不远了,但在helper类上仍然需要两个间接,不能将其编写为临时对象:

friend std::istream& operator>>(std::istream& in, MyClass& val) {
 in >>  ScanTo<enSide>(val.mSide)>> ScanTo<enType>(val.mType) >> val.mTargetId;        
 return in;      
}
friend std::istream&operator>>(std::istream&in,MyClass&val){
在>>ScanTo(val.mSide)>>ScanTo(val.mType)>>val.mTargetId中;
返回;
}
未编译(gcc 4.43),因为如注释中所述,禁止对临时文件进行非常量引用

所以问题来了:

如果不使用上述临时文件和模板,是否可以更轻松地完成此操作?


我认为您可以编写一个助手函数模板:

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

可能。

最好的选择是将数据成员定义为
int
,并使用类型安全访问器设置和检索它们

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; 
};
class-MyClass{
公众:
friend std::istream&operator>>(std::istream&in,MyClass&val){
在>>val.mSide>>val.mType>>val.mTargetId中;
返回;
}
MyClass(){}
enSide侧()常量{return static_cast(mSide);}
空侧(enSide v){mSide=v;}
enType type()常量{return static_cast(mType);}
无效类型(enType v){mType=v;}
int targetId()常量{return mTargetId;}
void targetId(int v){mTargetId=v;}
私人:
int-mSide;
int-mType;
int-mTargetId;
};

这就避免了你想要的临时性问题。

你看到了吗?浓缩版可与我的VS2010完美地编译(并运行)。您使用的编译器是什么?@dionadar我认为VS允许通过扩展将临时变量(
ScanTo(val.mSide)
)绑定到对非常量(
myClass&val
)的引用。这是非标准的。@kol:是的,但这意味着每个枚举都有一个单独的函数。我有很多东西;-)@dionadar:我使用的是gcc版本4.4.3,正如jrok指出的,将临时变量绑定到非常量引用似乎更为严格,这会杀死你,因为它可以被任意类型触发。如果您忘记为自定义类型定义运算符>>,但仍要使用它。您的代码将进行编译,但将int类型转换为任何自定义类型
in >> val.mSide >> val.mType >> val.mTargetId;
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; 
};