Search code examples
c++boostc++11lexical-cast

Template specialization for char pointer?


boost::lexical_cast is a great tool but in my application I ran into a limitation in string -> bool conversion that is bugging me. I need to convert all strings like "0", "false" and "FALSE" into false and "1", "true" and "TRUE" into true.

boost::lexical_cast only support conversion from/to "0" and "1". So my idea was to write my own conversion function which seems to work fine:

bool str_to_bool(const std::string &str)
{
    if(str == "1" || str == "true" || str == "TRUE")
        return true;
    else if(str == "0" || str == "false" || str == "FALSE")
        return false;
    else
        throw std::runtime_error("Bad cast from std::string to bool!");
}

Now I wan to write a wrapper round boost::lexical_cast and write my own template specializations for it. Here is what I've got so far:

template<typename Target, typename Source>
inline Target my_cast(const Source& src)
{
    return boost::lexical_cast<Target>(src);
}

template<>
inline bool my_cast(const std::string& src)
{
    return str_to_bool(src);
}

This works great for integers or std::string but obviously fails for string literals or character pointers:

int main(int argc, char* argv[])
{
    std::cout << my_cast<bool>(1) << std::endl;                    //OK
    std::cout << my_cast<bool>(std::string("true")) << std::endl;  //OK
    std::cout << my_cast<bool>("true") << std::endl;               //Fail! 

    return 0;
}

So I tried to write another specialization for char * but it fails to compile!

//does not compile!
template<>
inline bool my_cast(const char*& src)
{
    return str_to_bool(src);
}

What is the correct way to support both std::string and char *?

EDIT 1: the title was stupid. Fixed it.

EDIT 2: I borrowed a solution from boost itself. Posted as a new answer.


Solution

  • Here is a solution that works. I got the idea from boost::lexical_cast itself:

    template<class T>
    struct array_to_pointer_decay
    {
        typedef T type;
    };
    
    template<class T, std::size_t N>
    struct array_to_pointer_decay<T[N]>
    {
        typedef const T * type;
    };
    
    template<typename Target, typename Source>
    Target my_cast_internal(const Source& s)
    {
        return boost::lexical_cast<Target>(s);
    }
    
    template<>
    inline bool my_cast_internal(const std::string& src)
    {
        return str_to_bool(src);
    }
    
    template<>
    inline bool my_cast_internal(const char* const& src)
    {
        return str_to_bool(src);
    }
    
    template<typename Target, typename Source>
    inline Target my_cast(const Source& s)
    {
        typedef typename array_to_pointer_decay<Source>::type src;
    
        return my_cast_internal<Target, src>(s);
    }
    

    The main challenge is to deal with array types. The array_to_pointer_decay converts any array type to the corresponding pointer type. The rest is easy now.