1

I am trying to come up with a case insensitive string, and I found the following on the web

http://www.gotw.ca/gotw/029.htm

So basically my code to come up with a case insensitive string is as follows

struct ci_char_traits : public std::char_traits<char> {

    static bool eq( char c1, char c2 )
    { return toupper(c1) == toupper(c2); }

    static bool ne( char c1, char c2 )
    { return toupper(c1) != toupper(c2); }

    static bool lt( char c1, char c2 )
    { return toupper(c1) <  toupper(c2); }

    static int compare(const char* s1, const char* s2, size_t n )
    { return memicmp( s1, s2, n ); }

private:
    static int memicmp(const void *s1, const void *s2, size_t n) {

        if (n != 0) {
            const unsigned char *p1 = (const unsigned char *)s1, *p2 = (const unsigned char *)s2;
            do {
                if (toupper(*p1) != toupper(*p2))
                    return (*p1 - *p2);
                p1++;
                p2++;
            } while (--n != 0);
        }
        return 0;
    }
};

// case insensitive string type definition
typedef std::basic_string<char, ci_char_traits> ci_string;

// provide standard output for case insensitive string
template<typename char_type, typename traits_type, typename allocator_type>
inline std::basic_ostream<char_type, traits_type>&
operator<<(std::basic_ostream<char_type, traits_type>& os,
           const std::basic_string<char_type, ci_char_traits, allocator_type>& str) {
    return std::__ostream_insert(os, str.data(), str.size());
}

so the type definition is the string. Now the problem I have, is that I can't get a function to work with this custom string as it works with a regular string. The following template function gets a value from the string, but the

template <typename T, class string_type, typename counter_type>
T stream_cast(const string_type& s) {

  typedef typename string_type::value_type char_type;
  typedef typename string_type::traits_type traits_type;

  typename std::basic_istringstream<char_type, traits_type> iss(s);

  T x;
  char c;
  if (!(iss >> x) || iss.get(c))
     cout<<"*** ERROR *** Bad Conversion!"<<endl;
  return x;
} 

I call this function to get a double from a string as follows:

ci_string str("2.0");
double test = stream_cast<double>(str);

But something is wrong with my definition of case insensitive string because the evaluation of the stream object through operator! always fails (the line !(iss >> x) is always true for this string type).

Does someone know why I'm having this problem? Thanks in advance for taking the time to read this long post.

aa

aaragon
  • 2,314
  • 4
  • 26
  • 60
  • I imagine that all the basic formatting operations are only defined for `char_traits`, so those overloads simply don't exist. You could work around this by using ordinary strings for I/O and just construct one string from another (e.g. `ci_string is(s.begin(), s.end());` etc.). – Kerrek SB Oct 09 '11 at 14:22
  • Interesting thing: the code compiled with VC++ 2010 runs as expected, but when compiled with gcc 4.5.3 it encounters with the above issue. – Eugene Oct 09 '11 at 14:43
  • I just spent another 2 hours trying to find out why this is happening. The badbit is set for this type of string but I have no idea why. I tried to write my own version of the function basic_istream<_CharT, _Traits>::_M_extract but at some point I stopped because I was not able to access protected members of the basic_istream class. This is driving me crazy... =/ – aaragon Oct 10 '11 at 08:59

1 Answers1

1

You wrote a custom output operator "operator>>", but not an input operator "operator<<", and that's the one you need.

This works great:

ci_string str("2.0");
std::cout << str << std::endl;

because of the operator>>.

But

std::cin >> str

does not.

Marshall Clow
  • 15,972
  • 2
  • 29
  • 45
  • Thanks Marshall for replying. I'll try to go back to that piece of code and add the operator. I wouldn't have figured this out by my own. – aaragon Jan 19 '12 at 09:35