views:

101

answers:

1

Is there any reason that the ctype facet functions (is,scan_is,scan_not only support plain char pointer, and not iterator based containers, like std::string or even a std::vector... then one could write:

const ctype<char>& myctype = use_facet<std::ctype<char> >(locale(""));
string foo_str = "hi there here is a number: 748574 and text again";
vector<char> foo(foo_str.begin(),foo_str.end());

//then one could write

vector<char>::iterator num_begin_it = myctype.scan_is( ctype<char>::digit, foo.begin(), foo.end() );
vector<char> foo_num_1( foo, num_begin_it, myctype.scan_not(ctype<char>::digit, num_begin_it, foo.end() );

//instead of:
const char* num_begin_pc = myctype.scan_is(ctype<char>::digit, &foo[0], &foo[foo.size()-1]+1); // &foo[foo.size()-1]+1) instead of foo.end() is not quite readable.
vector<char> foo_num_2(num_begin_pc, myctype.scan_not(ctype<char>::digit, num_begin_pc, &foo[foo.size()-1]+1));

//appendix:
//STL/Boost solution, even more verbose:

function<bool(char)> is_digit_func =
    bind(
        mem_fn(static_cast<bool (ctype<char>::*)(ctype<char>::mask,char) const>(&ctype<char>::is)),
        &myctype,
        ctype<char>::digit,
        _1
    );
vector<char>::iterator num_begin_0x = find_if(foo.begin(), foo.end(),is_digit_func);
vector<char> foo_num_3(num_begin_0x,find_if(num_begin_0x, foo.end(),not1(is_digit_func)));

// all 3 foo_num_X will now contain "748574"

Would be cool if anyone has some insight why the standard committee made those design decisions ?

And is there a better (=less verbose) way to make use of the ctype functions with iterator-based containers ?

The STL/Boost solution would be kinda OK, if it wouldnt need that

Additionally i found that there is no copy_if algorithm in the standard library, but i already the reason for this.

+2  A: 

The main reason is that the Standard Library wasn't developed as a single coherent whole, but incorporates several libraries that were popular at the time.

Iterators were a concept from the "Standard Template Library", which was the basis for the standard Containers, Iterators and Algorithms libraries. The Strings and Localization libraries came from other sources, which did not use iterators. Because iterators are so useful, it was deemed worth the effort of retrofitting them to these libraries, but not to completely change the libraries' interfaces to use iterators everywhere.

By the way, you might find &foo.back()+1 or &foo[0] + foo.size() to be more readable than &foo[foo.size()-1]+1. You also don't need to copy the string into a vector to use scan_is and scan_not; something like this should do the job:

const char* str_begin = foo_str.c_str();
const char* str_end   = str_begin + foo_str.length();
const char* num_begin = myctype.scan_is(ctype<char>::digit, str_begin, str_end);
const char* num_end   = myctype.scan_not(ctype<char>::digit, num_begin, str_end);
std::string number(num_begin, num_end); // or `vector` if you really want
Mike Seymour
i only have an intermediate std::string, because you cant initialize a vector nicely with an string literal. And i wanted an example with vector.
smerlin
After they adopted the STL, they have added iterators to `std::string` but not to `std::ctype`. This seems very inconsistent to me, especially since they wouldnt have to change the customer-view of the interface at all a `template<class InputIt> scan_is(mask m, InputIt low, InputIt low) const` would not behave different when called with `const char*` then the `const char*`-only interface.IMO the complete locale library feels like C-with-Classes, especially ctype and codecvt.
smerlin