Jam*_*lis 22 c++ enums serialization casting lexical-cast
我有以下函数将字符串转换为数字数据类型:
template <typename T>
bool ConvertString(const std::string& theString, T& theResult)
{
std::istringstream iss(theString);
return !(iss >> theResult).fail();
}
Run Code Online (Sandbox Code Playgroud)
但这不适用于枚举类型,所以我做了类似这样的事情:
template <typename T>
bool ConvertStringToEnum(const std::string& theString, T& theResult)
{
std::istringstream iss(theString);
unsigned int temp;
const bool isValid = !(iss >> temp).fail();
theResult = static_cast<T>(temp);
return isValid;
}
Run Code Online (Sandbox Code Playgroud)
(我假设theString具有枚举类型的有效值;我主要用于简单序列化)
有没有办法创建一个结合这两者的单一功能?
我已经使用了模板参数,但没有提出任何建议; 如果不必为枚举类型调用一个函数而为其他所有函数调用另一个函数,那就太好了.
谢谢
Joh*_*itb 43
你必须做两个步骤.找到一个足以存储值的整数类型.您可以使用unsigned long
,但值可能是负数.然后你可以使用,long
但值可以扩展到范围unsigned long
.所以没有真正适合它的类型.
但是,通过使用重载解析,有一个技巧.就这个
template<typename T>
struct id { typedef T type; };
id<char[1]>::type &find_etype(int);
id<char[2]>::type &find_etype(unsigned int);
id<char[3]>::type &find_etype(long);
id<char[4]>::type &find_etype(unsigned long);
Run Code Online (Sandbox Code Playgroud)
您可以适当地更改它以覆盖long long
或者unsigned long long
您的实现是否支持.现在,传递枚举类型将优先于其他所有类型 - 这是一种可以存储它的所有值的类型.您只需sizeof
将返回类型传递给某个模板即可.
template<int> struct get_etype;
template<> struct get_etype<1> { typedef int type; };
template<> struct get_etype<2> { typedef unsigned int type; };
template<> struct get_etype<3> { typedef long type; };
template<> struct get_etype<4> { typedef unsigned long type; };
Run Code Online (Sandbox Code Playgroud)
现在,您可以获得正确的类型.您现在需要的是查看某些类型是否为枚举.如何执行此操作在"C++模板 - 完整指南"一书中有所描述,遗憾的是它是一大堆代码.所以我会使用boost is_enum
.把它放在一起,它看起来像
template <typename T>
typename boost::disable_if< boost::is_enum<T>, bool>::type
ConvertString(const std::string& theString, T& theResult)
{
std::istringstream iss(theString);
return !(iss >> theResult).fail();
}
template <typename T>
typename boost::enable_if< boost::is_enum<T>, bool>::type
ConvertString(const std::string& theString, T& theResult)
{
typedef typename get_etype<sizeof find_etype(theResult)>::type
safe_type;
std::istringstream iss(theString);
safe_type temp;
const bool isValid = !(iss >> temp).fail();
theResult = static_cast<T>(temp);
return isValid;
}
Run Code Online (Sandbox Code Playgroud)
希望这可以帮助.
GMa*_*ckG 10
只是为了"完成"这个问题,在C++ 0x中我们可以这样做:
typedef typename std::underlying_type<T>::type safe_type;
Run Code Online (Sandbox Code Playgroud)
代替约翰内斯的get_etype
伎俩.