Hi,
In Item 35 of "Effective STL", Scott Meyers says to "Implement simple case-insensitive string comparisons via mismatch or lexicographical_compare".
I can see how the mismatch version would work, but when I tried creating a string comparison function with lexicographical_compare(), it isn't working because lexicographical_compare() only returns true "if the range of elements [start1,end1) is lexicographically less than the range of elements [start2,end2)".
I tried adding a not2() around the predicate, but that didn't help.
I have almost the same code as the book (except I'm using the C++ tolower() function)...
Code:
/** ToLowerChar
* This is a functor that wraps the std::tolower() function.
*/
template <typename E>
class ToLowerChar : public std::binary_function<E, std::locale, E>
{
public:
/** ToLowerChar()
* A constructor for the ToLowerChar functor that sets the Locale to use when converting
* the characters to lower-case.
*
* @param loc [IN] - The locale to use for character conversions.
*/
ToLowerChar( const std::locale& loc = std::locale() )
: m_Locale( loc ) {}
/** operator()
* This operator will return a lower-case version of the character passed to it.
*
* @param ch [IN] - This is the character to convert to lower-case.
*
* @param loc [IN] - (optional) This is the locale to use.
*
* @return E - The lower-case version of the character that was passed in.
*/
E operator()( E ch ) const
{
return std::tolower( ch, m_Locale );
}
private:
const std::locale& m_Locale; /**< This is the locale to use for character conversions. */
};
/** CharLessNoCase
* A functor to compare 2 characters without regard to case.
*/
template <typename E>
class CharLessNoCase : public std::binary_function<E, E, bool>
{
public:
/** CharLessNoCase()
* A constructor for the CharLessNoCase functor that sets the Locale to use when converting
* the characters to lower-case.
*
* @param loc [IN] - The locale to use for character conversions.
*/
CharLessNoCase( const std::locale& loc = std::locale() )
: m_Locale( loc ) {}
/** operator()
* First converts both characters to lower-case, then returns true if they
* are the same or false if they're not.
*
* @param c1 [IN] - The first character to compare.
*
* @param c2 [IN] - The second character to compare.
*
* @return bool - true if the characters are the same (ignoring case),
* otherwise false if they're different.
*/
bool operator()( E c1, E c2 ) const
{
return (ToLowerChar<E>( m_Locale )( c1 ) < ToLowerChar<E>( m_Locale )( c2 ));
}
private:
const std::locale& m_Locale; /**< This is the locale to use for character conversions. */
};
/** StringCompareNoCase
* This functor compares 2 STL strings without regard to case.
*/
template <typename E,
typename T = std::char_traits<E>,
typename A = std::allocator<E> >
class StringCompareNoCase : public std::binary_function<const std::basic_string<E, T, A>&,
const std::basic_string<E, T, A>&,
bool>
{
public:
/** StringCompareNoCase()
* A constructor for the StringCompareNoCase functor that sets the Locale to use when converting
* the characters to lower-case.
*
* @param loc [IN] - The locale to use for character conversions.
*/
StringCompareNoCase( const std::locale& loc = std::locale() )
: m_Locale( loc ) {}
/** operator()
* Compares 2 STL strings without regard to case.
*
* @param str1 [IN] - The first string to compare.
*
* @param str2 [IN] - The second string to compare.
*
* @return bool - true if the strings are the same (ignoring case),
* otherwise false if they're different.
*/
bool operator()( const std::basic_string<E, T, A>& str1,
const std::basic_string<E, T, A>& str2 ) const
{
return std::lexicographical_compare( str1.begin(), str1.end(),
str2.begin(), str2.end(),
CharLessNoCase<E>( m_Locale ) );
}
private:
const std::locale& m_Locale; /**< This is the locale to use for character conversions. */
};
Am I doing something wrong, or did I completely misunderstand what Scott was talking about?