基于空终止字符串的循环的范围

Mot*_*tti 14 c++ for-loop null-terminated c++11

我有点假设基于for循环的范围会支持C风格的字符串

void print_C_str(const char* str)
{
    for(char c : str)
    {
        cout << c;
    }
}
Run Code Online (Sandbox Code Playgroud)

然而事实并非如此,标准[stmt.ranged] (6.5.4)表示基于范围的工作有以下三种可能性之一:

  1. 范围是一个数组
  2. 范围是一个具有可调用beginend方法的类
  3. 在关联的命名空间(加上std命名空间)中可以访问ADL

当我在全局命名空间中添加beginend函数时,const char*我仍然会收到错误(来自VS12和GCC 4.7).

有没有办法让基于范围的for循环与C样式字符串一起使用?

我尝试添加一个重载namespace std,这是有效的,但据我的理解,添加重载namespace std是非法的(这是正确的吗?)

R. *_*des 20

如果为空终止字符串编写一个简单的迭代器,可以通过调用返回特殊范围的指针上的函数来完成此操作,而不是将指针本身视为范围.

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, {});
}
Run Code Online (Sandbox Code Playgroud)

用法如下:

for(char c : null_terminated_string(str))
{
    cout << c;
}
Run Code Online (Sandbox Code Playgroud)

我不认为这会失去任何表现力.实际上,我认为这个更清楚.

  • +1,它*是*更干净,因为它正确地适用于`char*`和`char []`.`char []`的问题在于它本地工作但做错了(它被视为任何C数组,而不是零终止字符串,因此是一个元素太长. (4认同)
  • @hmjd是的,`for(char c:std :: string(str))`是另一种选择.这种方法优于std :: string的优点是这种抽象具有非常低的运行时成本:构造的额外对象非常便宜,不像std :: string可能涉及动态分配并将整个字符串复制到自己的缓冲.基本上,虽然我不会嘲笑看到用于此的std :: string(除非分析证明它是性能问题),这提供了所需的功能,迭代,而std :: string提供了不需要的功能,这就是成本. (2认同)