【问题标题】:How to read enums from a std::istream in a generic fashion [duplicate]如何以通用方式从 std::istream 读取枚举[重复]
【发布时间】:2012-06-24 12:52:11
【问题描述】:

可能重复:
Input from stream to enum type

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

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

  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; 
  };

很遗憾,这不起作用,因为无法直接读取 enum 值(没有 >> 的模板)。

因此我创建了一个辅助类:

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;    
};

现在我可以编写读取MyClass的代码如下:

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;      
}

这已经离我想要的不远了,但仍然需要对辅助类进行两次间接处理,这不能写成临时的:

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

不编译 (gcc 4.43),因为正如 cmets 中所指出的那样,禁止对临时对象进行非 const 引用。

那么问题来了:

如果不使用上述的一些临时工具和模板,这是否可以更轻松地完成?

【问题讨论】:

  • 精简版与我的 VS2010 完美地编译(和工作)。你用的是什么编译器?
  • @dionadar 我认为 VS 允许通过扩展将临时变量 (ScanTo&lt;enSide&gt;(val.mSide)) 绑定到对非常量 (myClass&amp; val) 的引用。不过,它是非标准的。
  • @kol:是的,但这意味着每个枚举都有一个单独的函数。我有负载;-)
  • @dionadar:我使用 gcc 版本 4.4.3,正如 jrok 指出的那样,将临时对象绑定到非 const 引用似乎更加严格

标签: c++ templates enums iostream


【解决方案1】:

我想你可以写一个辅助函数模板:

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

这让

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

可能。

【讨论】:

  • 这会杀死你,因为它可以被任意类型触发。如果您忘记为自定义类型定义运算符 >> 但无论如何都要使用它。您的代码将编译但将 int 类型转换为任何自定义类型
【解决方案2】:

您的最佳选择是将您的数据成员定义为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; 
};

这样可以避免你想要的临时性。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-09-13
    • 1970-01-01
    • 2010-12-21
    • 1970-01-01
    • 2010-11-21
    • 2014-02-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多