为什么 std::basic_string::substr 不遵循 [begin, end) 约定?
Why doesn't std::basic_string::substr follow the [begin, end) convention?
方法 std::basic_string::substr
has the arguments pos, count
, specifying the logical range of elements in positions [pos, pos + count + 1). Conversely, most of the standard library functions (for example, std::for_each
) 有参数,某种形式类似于 begin, end
,指定范围 [begin, end)
这似乎是一个例外,然后,让一些人感到困惑(参见问题here, here, here, and here). Why wasn't the usual range convention used here? Note also that std::vector::erase
,另一个随机访问容器的方法,确实遵循通常的惯例。
一个简单的猜测:
您引用的不同方法有不同的行为,这可能就是为什么有些人使用迭代器而有些人不使用的原因。
std::for_each
是通用的 - 拥有适用于任何容器(甚至原始数组)的方法的通用版本的最简单方法是使用迭代器。
std::vector::erase
是 SequenceContainer 概念的一部分,因此它必须具有可以在任何类型的容器上工作的 "generic" 形式(您可以使用 pos
和count
表示 std::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
的一部分(不像 erase
是 std::vector
、std::list
、... ) 和 returns a std::basic_string
1(不是迭代器,你在这里用迭代器做什么?)。
std::basic_string
中还有其他 "non-generic"(即某些概念不是强制性的)方法,通常是整个 find
方法家族,insert
有一个用 size_type
、append
等重载。
从主观的角度来看,我认为 std::basic_string
的行为与其他容器不同,因为它不是(我不确定标准是否要求 std::basic_string
SequenceContainer
或类似的东西)。
1 你不能在这里使用 return 迭代器,因为你想要一个新的 std::basic_string
,所以你会有一个采用迭代器的方法但是return 一个对象...我会发现这比 pos
/count
而不是 first
/last
. 更令人不安
我不能说为什么,我不在那里,但是有一个范围构造函数用于您错过的 [begin, end) 约定。
template< class InputIt >
basic_string( InputIt first, InputIt last,
const Allocator& alloc = Allocator() );
历史原因。标准库有多个起源,STL 就是其中之一。它带来了 begin,end
约定。 std::string
早于 STL 合并到标准库中,并且有大量现有代码使用了 .substr(pos,length)
。
方法 std::basic_string::substr
has the arguments pos, count
, specifying the logical range of elements in positions [pos, pos + count + 1). Conversely, most of the standard library functions (for example, std::for_each
) 有参数,某种形式类似于 begin, end
,指定范围 [begin, end)
这似乎是一个例外,然后,让一些人感到困惑(参见问题here, here, here, and here). Why wasn't the usual range convention used here? Note also that std::vector::erase
,另一个随机访问容器的方法,确实遵循通常的惯例。
一个简单的猜测:
您引用的不同方法有不同的行为,这可能就是为什么有些人使用迭代器而有些人不使用的原因。
std::for_each
是通用的 - 拥有适用于任何容器(甚至原始数组)的方法的通用版本的最简单方法是使用迭代器。
std::vector::erase
是 SequenceContainer 概念的一部分,因此它必须具有可以在任何类型的容器上工作的 "generic" 形式(您可以使用 pos
和count
表示 std::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
的一部分(不像 erase
是 std::vector
、std::list
、... ) 和 returns a std::basic_string
1(不是迭代器,你在这里用迭代器做什么?)。
std::basic_string
中还有其他 "non-generic"(即某些概念不是强制性的)方法,通常是整个 find
方法家族,insert
有一个用 size_type
、append
等重载。
从主观的角度来看,我认为 std::basic_string
的行为与其他容器不同,因为它不是(我不确定标准是否要求 std::basic_string
SequenceContainer
或类似的东西)。
1 你不能在这里使用 return 迭代器,因为你想要一个新的 std::basic_string
,所以你会有一个采用迭代器的方法但是return 一个对象...我会发现这比 pos
/count
而不是 first
/last
. 更令人不安
我不能说为什么,我不在那里,但是有一个范围构造函数用于您错过的 [begin, end) 约定。
template< class InputIt >
basic_string( InputIt first, InputIt last,
const Allocator& alloc = Allocator() );
历史原因。标准库有多个起源,STL 就是其中之一。它带来了 begin,end
约定。 std::string
早于 STL 合并到标准库中,并且有大量现有代码使用了 .substr(pos,length)
。