How can I extend a lexical cast to support enumerated types?

别说谁变了你拦得住时间么 提交于 2019-11-27 07:07:16

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

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

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

Hope this helps.

And just to "complete" the question, in C++0x we can just do this:

typedef typename std::underlying_type<T>::type safe_type;

In place of Johannes get_etype trick.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!