0

I'm reading Herb Sutter's book Exceptional C++, and in the second item you need to write a case insensitive string class ci_string with the following behavior:

#include <assert.h>

ci_string s("AbCdE");

// case insensitive
//
assert(s == "abcde");
assert(s == "ABCDE");
// still case-preserving, of course
//
assert(strcmp(s.c_str(), "AbCdE") == 0);
assert(strcmp(s.c_str(), "abcde") != 0);

My idea was to make this class the same as std::string, and only to overwrite operator== :

#include <string>
#include <cctype>

using namespace std;

struct ci_string : string {

    bool operator==(const ci_string& lhs) {
        if (this->length() != lhs.length())
            return false;
        for (size_type i = 0; i != this->length(); ++i) {
            if (tolower((*this)[i]) != tolower(lhs[i]))
                return false;
        }
        return true;
    }
};

but, this code doesn't compile if you combine it with the first one, because there is no appropriate constructor of ci_string for const char[] as "AbCdE", although the parent class has one.

What is the most elegant way to solve this? I want the code to be as short as possible, without the need to rewrite string's constructors and member functions like c_str() etc.

Andrey S
  • 151
  • 6

1 Answers1

3

A more elegant way of solving the problem is using char_traits as shown in the answer.

But to avoid boilerplate code with your approach, you can "copy" the parent's constructors with using string::string; inside the child class.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • What I get if I try to put `using string::string;` inside the child class is: `error C2039: 'string' : is not a member of 'std::basic_string,std::allocator>' ` – Andrey S Aug 20 '14 at 07:32
  • Hmm, it does work on my compiler. Perhaps try to use the actual type which the `std::string` is a typedef of: `using basic_string::basic_string;` – eerorika Aug 20 '14 at 07:38
  • now it's `error C2886: 'basic_string,std::allocator>' : symbol cannot be used in a member using-declaration` – Andrey S Aug 20 '14 at 07:49
  • This feature was introduced in c++11. It seems that your compiler doesn't support it yet. You'll have to define a constructor for each constructor of `std::string` and delegate them to the parent. – eerorika Aug 20 '14 at 08:09
  • I'm not sure I understand. If you define a case insensitive char traits (probably be deriving from `std::char_traits` and overriding the few functions which need to be changed), there is no constructor which needed to be copied; you're still using `std::basic_string`. (On the other hand, you _will_ need to implement the `<<` and `>>` operators and `getline`; the standard versions require the same `char_traits` for the stream and the string.) – James Kanze Aug 20 '14 at 09:23