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.
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.