我有点假设为基础的循环将支持C风格的字符串范围
void print_C_str(const char* str)
{
for(char c : str)
{
cout << c;
}
}
然而,这不是这种情况,该标准[stmt.ranged] (6.5.4)
表示,范围为基础的换在3种可能性之一工作:
- 范围是一个数组
- 的范围是与一个可调用一类
begin
和end
的方法 - 有ADL可达在相关命名空间(加上
std
命名空间)
当我添加begin
和end
的功能const char*
全局命名空间我仍然得到错误(来自VS12和GCC 4.7)。
有没有办法让范围为基础,对循环使用C风格的字符串工作吗?
我尝试添加的过载namespace std
和这个工作,但我的理解是违法添加的过载到namespace std
(这是正确的?)
如果你写null结尾的字符串一个平凡的迭代器,你可以通过调用返回一个特殊的范围内,指针的函数,而不是治疗指针本身的范围内做到这一点。
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, {});
}
和使用情况如下:
for(char c : null_terminated_string(str))
{
cout << c;
}
我不认为这将失去任何表现。 其实,我觉得这是一个更加清晰。
A C-string是不是一个数组,它不具有类begin
/ end
成员,因为该参数是一个原始的,你将不会被ADL发现任何东西。 按理说,这应该是纯不合格查找,与ADL,它会发现在全局命名空间的功能。 但是,考虑措辞,我想这是不可能的。
一个可能的解决方法是包裹空在另一种类型的终止字符串。 最简单的实现如下(比是少高性能R.费尔南德斯Martinho的建议,因为它会调用strlen
,但它也是显著更少的代码)。
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); }
};
用法:
for(char c : null_terminated_range(str) )