I recently had a bug where extracting a decimal from a string failed due to locale settings. That is, some locales use a ,
as a decimal point, rather than a .
. An important goal is that the conversion function is deterministic.
I have usually used boost::lexical_cast
for such tasks, but my understanding is that this is reliant on the global application locale. I have therefore implemented a variant of lexical_cast
that uses the std::locale::classic
"C" locale for the conversion.
#include <type_traits>
#include <locale>
#include <string>
#include <sstream>
#include <stdexcept>
namespace typeconv
{
/**
* Convert @c str to a T
*
* @param str string to convert to a T
* @return the value contained within @c as a T
*
* @pre @c str is arithmetic and can be converted to a T
* @note std::locale::classic() is used for the conversion.
*
* @throws std::invalid_argument if str cannot be converted to an object of type T.
*/
template<typename T>
inline auto lexical_cast(const std::string& str)
-> typename std::enable_if<std::is_arithmetic<T>::value, T>::type
{
std::istringstream istr(str);
istr.imbue(std::locale::classic());
T val;
istr >> val;
if (istr.fail())
throw std::invalid_argument(str);
return val;
}
}
I plan to extend the template function in future to include other conversions, such as an arithmetic type to std::string
. Any comments on the implementation are welcome.