如何扩展一个词法转换以支持枚举类型? [英] How can I extend a lexical cast to support enumerated types?

查看:162
本文介绍了如何扩展一个词法转换以支持枚举类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下函数将字符串转换为数字数据类型:

I have the following function that will convert a string into a numeric data type:

template <typename T>
bool ConvertString(const std::string& theString, T& theResult)
{
    std::istringstream iss(theString);
    return !(iss >> theResult).fail();
}

但是,这对枚举类型不起作用,所以我做了一些这个:

This does not work for enumerated types, however, so I have done something like this:

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

(我假设theString有枚举的有效值类型;我使用这个主要是为了简单的序列化)

(I'm making the assumption that theString has a valid value for the enumerated type; I'm using this mainly for simple serialization)

有没有办法创建一个结合这两个功能的单一功能?

Is there a way to create a single function that combines both of these?

我已经玩了一些模板参数,但没有提出任何东西;只需调用一个枚举类型的函数,另一个函数就可以调用其他函数。

I've played a bit with the template arguments but haven't come up with anything; it'd just be nice not to have to call one function for enumerated types and another for everything else.

谢谢

推荐答案

你必须做两个步骤。找到一个足够大的积分类型来存储值。您可以使用 unsigned long ,但值可能为负。然后,您可以使用 long ,但值可以扩展到 unsigned long 的范围。所以没有真正的适合所有类型。

You have to do two steps. Finding an integral type large enough to store the values. You could use unsigned long, but the values could be negative. Then you could use long but the values could extend into the range of unsigned long. So there is not really a fit-it-all type.

有一个技巧,通过使用重载分辨率。这是它

There is a trick though, by using overload resolution. Here is it

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

您可以适当更改以涵盖 long long unsigned long long 如果您的实现有支持。现在,传递一个枚举类型将会优先于其他所有类型 - 这是一种可以存储所有值的类型。您只需将返回类型的 sizeof 传递给某个模板。

You can change it appropriately to cover also long long or unsigned long long if your implementation has support for that. Now, passing an enum type will prefer one of these over all the other ones - that's a type that can store all values of it. You just need to pass sizeof of the return type to some template.

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

现在,您可以获得正确的类型。您现在需要查看某些类型是否是枚举。如何做到这一点在C ++模板 - 完整指南一书中有所描述,不幸的是有很多代码。所以我会使用boost的 is_enum 。把它放在一起,可能看起来像

Now, you can get a right type. All you need now is to see whether some type is an enumeration. How to do this is described in the book "C++ Templates - The complete Guide", and unfortunately is a whole lot of code. So i would use boost's is_enum. Putting it together, it could look like

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

希望这有帮助。

这篇关于如何扩展一个词法转换以支持枚举类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆