The following program throws a bad_cast during sorting of a vector of strings, but I am not aware that I am using a cast. For the comparision, I am using a function object.
Why doesn't this give a compile time error? Is because you can construct a string from a char like this std::string{'c'};? But then why is it using dynamic_cast?
It uses tolower overload from <locale>. It uses facets which does some runtime checks on input types and throws bad_cast if they can't makes sense of input type.
His problem is that he is trying to use tolower on strings. Which is not going to work no matter what overload he will use.
Solution is to either store char instead of strings, or compare first characters of strings (or use transform to change whole strings and compare strings if he want that)
struct CompFunc {
// Do case-insensitive string comparision
inlinebooloperator()(string s1, string s2) {
static locale loc; // *** static added
return tolower(s1,loc) < tolower(s2,loc);
}
////////////// added /////////////////////////
// return string converted to all lower case using the ctype facet in locale
static std::string tolower( std::string s, const std::locale& loc )
{
for( std::size_t i = 0 ; i < s.size() ; ++i ) s[i] = std::tolower( s[i], loc ) ;
return s ;
}
///////////////////////////////////////////////
} compfunc;
> Why doesn't this give a compile time error?
> But then why is it using dynamic_cast?
template< typename CHAR_TYPE > CHAR_TYPE std::tolower( CHAR_TYPE c, const locale& loc );
is instantiated with CHAR_TYPE == std::string.
The instantiation invokes std::use_facet< std::ctype<std::string> >(loc)
which throws std::bad_cast because std::has_facet< std::ctype<std::string> >(loc) is false.
(This IS specifies that std::bad_cast must be thrown in this case.)
Thanks to all. I don't know what I had in mind when thinking that the template version of std::tolower would for sure have a specialization for std::string! This idea sounded so obvious to me, that I didn't bother to check the standard. Oh my, I did too much programming in Python, Ruby and Perl lately...
Thank you for the good explanations. I'm surprised that the C++ standard doesn't provide a library function for this common task. I will go with the solution by JLBorges.
I'm surprised that the C++ standard doesn't provide a library function for this common task.
It is because it is actually some advanced capabilities, with a fairly large data add-in to your program. Many libraries already exist to do this (ICU, for example).
The problem is that converting string case is not a trivial task.