为什么 std::basic_string::substr 不遵循 [begin, end) 约定?

Why doesn't std::basic_string::substr follow the [begin, end) convention?

本文关键字:begin end 约定 basic std string substr 为什么      更新时间:2023-10-16

方法std::basic_string::substr有参数pos, count,指定位置[pos, pos + count + 1)中的元素的逻辑范围。相反,大多数标准库函数(例如,std::for_each)都有与begin, end类似形式的参数,指定范围[begin, end]

这似乎是一个例外,让一些人感到困惑(参见这里,这里,这里和这里的问题)。为什么这里没有使用通常的范围约定?还要注意std::vector::erase,另一个随机访问容器的方法,遵循通常的约定。

历史原因

标准库有多个来源,其中之一就是STL。它带来了begin,end大会。std::string在STL合并到标准库之前就出现了,并且有很多现有的代码使用了.substr(pos,length)

一个简单的猜测:

你引用的不同方法有不同的行为,这可能就是为什么有些方法使用迭代器而有些方法不使用的原因。

std::for_each是泛型的——拥有一个在任何容器(甚至是原始数组)上工作的方法的泛型版本最简单的方法是使用迭代器。

std::vector::erase是SequenceContainer概念的一部分,所以它必须有一个"通用"的形式,可以在任何类型的容器上工作(你可以使用poscountstd::vector,但std::list呢?还是std::set ?)。拥有这样的概念对于创建泛型代码很有用:

template <typename C>
void real_remove(C &c, const typename C::value_type &value) {
     c.erase(std::remove(c.begin(), c.end(), value), c.end());
}

这只能工作,因为std::...::erase是为任何SequenceContainer定义的。

另一方面,std::basic_string::substr只是std::basic_string的一部分(不像erasestd::vector, std::list,…的一部分),并返回std::basic_string 1(不是迭代器,在这里你会用迭代器做什么?)

std::basic_string中还有其他"非泛型"(即某些概念不是强制性的)方法,通常是find方法的整个家族,insertsize_type, append等有过载。

从主观角度来看,我认为最好有一个不像其他容器那样行为的std::basic_string,因为它不是(我不确定标准是否要求std::basic_stringSequenceContainer或类似的东西)。

1这里不能返回迭代器,因为你想要一个新的std::basic_string,所以你会有一个接受迭代器但返回对象的方法…我觉得这比用pos/count代替first/last更令人不安。

我不能说为什么,我不在那里,但是对于您错过的[begin, end]约定,有一个范围构造函数。

template< class InputIt >
basic_string( InputIt first, InputIt last,
              const Allocator& alloc = Allocator() );