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

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

问题描述

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

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

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

(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天全站免登陆