Range based for loops on null terminated strings

自闭症网瘾萝莉.ら 提交于 2019-11-30 11:33:19

If you write a trivial iterator for null-terminated strings, you can do this by calling a function on the pointer that returns a special range, instead of treating the pointer itself as the range.

template <typename Char>
struct null_terminated_range_iterator {
public:
    // make an end iterator
    null_terminated_range_iterator() : ptr(nullptr) {}
    // make a non-end iterator (well, unless you pass nullptr ;)
    null_terminated_range_iterator(Char* ptr) : ptr(ptr) {}

    // blah blah trivial iterator stuff that delegates to the ptr

    bool operator==(null_terminated_range_iterator const& that) const {
        // iterators are equal if they point to the same location
        return ptr == that.ptr
            // or if they are both end iterators
            || is_end() && that.is_end();
    }

private:
    bool is_end() {
        // end iterators can be created by the default ctor
        return !ptr
            // or by advancing until a null character
            || !*ptr;
    }

    Char* ptr;
}

template <typename Char>
using null_terminated_range = boost::iterator_range<null_terminated_range_iterator<Char>>;
// ... or any other class that aggregates two iterators
// to provide them as begin() and end()

// turn a pointer into a null-terminated range
template <typename Char>
null_terminated_range<Char> null_terminated_string(Char* str) {
    return null_terminated_range<Char>(str, {});
}

And usage looks like this:

for(char c : null_terminated_string(str))
{
    cout << c;
}

I don't think this loses any expressiveness. Actually, I think this one is clearer.

A C-string is not an array, it is not a class that has begin/end members, and you won't find anything by ADL because the argument is a primitive. Arguably, this should be plain unqualified lookup, with ADL, which would find a function in the global namespace. But, given the wording, I'm thinking that it is not possible.

Motti

A possible workaround is to wrap the null terminated string in another type. The simplest implementation is as follows (it's less performant than R. Martinho Fernandes's suggestion since it calls strlen but it's also significantly less code).

class null_terminated_range {
    const char* p:
public:
    null_terminated_range(const char* p) : p(p) {}
    const char * begin() const { return p; }
    const char * end() const { return p + strlen(p); }
};

Usage:

for(char c : null_terminated_range(str) ) 
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!