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