utilities.hpp case insensitive comparison broken #281

Closed
Toninoso opened this Issue Jul 27, 2013 · 2 comments

Projects

None yet

1 participant

@Toninoso

This is compiling echo server with Visual Studio 2012 Update 3 on Windows 8.

Need to add locale header.

#include <algorithm>
#include <string>
#include <locale>  // without this get following 2 errors

Error 1 error C2039: 'tolower' : is not a member of 'std'
Error 2 error C2660: 'tolower' : function does not take 2 arguments

After locale header was added, std::tolower inside ci_less has to use it:

struct ci_less : std::binary_function<std::string, std::string, bool> {
    // case-independent (ci) compare_less binary function
    struct nocase_compare 
      : public std::binary_function<unsigned char,unsigned char,bool>
    {
    std::locale loc;
        bool operator() (unsigned char const & c1, unsigned char const & c2) const {
            return std::tolower (c1, loc) < std::tolower (c2, loc);
       }
    };

This appears correct (i.e. non MSVC specific) as per:

http://www.cplusplus.com/reference/locale/tolower/

@zaphoyd zaphoyd closed this in 485304b Jul 27, 2013
@Toninoso

Apparently that is not enough since std::tolower() used in ci_less functor still expects locale parameter.

I followed your example of my_equal in utilities.hpp and implemented ci_less in the similar way:

struct ci_less : std::binary_function<std::string, std::string, bool> {
    struct nocase_compare 
    {
        bool operator() (unsigned char const & c1, unsigned char const & c2, std::locale const & loc) const {
            return std::tolower (c1, loc) < std::tolower (c2, loc); 
        }
    };

    ci_less(std::locale const & loc = std::locale()) : m_loc(loc) {}

    bool operator() (std::string const & s1, std::string const & s2) const {
        return std::lexicographical_compare 
            (s1.begin (), s1.end (),   // source range
            s2.begin (), s2.end (),   // dest range
            std::bind(nocase_compare(), std::placeholders::_1, std::placeholders::_2, m_loc));  // comparison
    }
private:
    std::locale m_loc;
};
@Toninoso

This is the last comment, I promise:

Probably you want to avoid requiring std::bind and std::placeholders, in which case the correct solution (I tested it) is this:

struct ci_less : std::binary_function<std::string, std::string, bool> {
    // case-independent (ci) compare_less binary function
    struct nocase_compare
      : public std::binary_function<unsigned char,unsigned char,bool>
    {
        nocase_compare(std::locale const & loc) : m_loc(loc) {}

        bool operator() (unsigned char const & c1, unsigned char const & c2) const {
            return std::tolower (c1, m_loc) < std::tolower (c2, m_loc); 
        }
    private:
        std::locale m_loc;
    };

    ci_less(std::locale const & loc = std::locale()) : m_loc(loc) {}

    bool operator() (std::string const & s1, std::string const & s2) const {
        return std::lexicographical_compare 
            (s1.begin (), s1.end (),   // source range
            s2.begin (), s2.end (),   // dest range
            nocase_compare(m_loc));  // comparison
    }
private:
    std::locale m_loc;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment