2016-09-28 128 views
2

方法std::basic_string::substr具有参数pos, count,指定位置[pos,pos + count + 1)中元素的逻辑范围。相反,大部分的标准库函数(例如,std::for_each)具有参数,某种形式的类似于begin, end的,指定范围[开始,结束)为什么std :: basic_string :: substr不遵循[begin,end]约定?

这似乎是一个例外,那么,混淆一些(见问题here,here,herehere)。为什么这里不使用惯常的范围约定?还请注意std::vector::erase,另一种随机存取容器的方法,确实按照惯例约定

+2

通过使用控制器可以获得相同的行为。例如。 'std :: string substring {text.begin(),text.end()}'。不知道为什么'substr'没有这样的过载。 – Zereges

+0

@Zereges:因为它是多余的。如果你有两个迭代器表示子字符串,为什么把它们传递给'std :: string :: substr()'重载,如果你也可以将它们传递给'std :: string :: string()'。 – MSalters

+0

@MSalters在STL中有很多冗余重载甚至函数。 STL的设计并非简约。 – Zereges

回答

5

历史原因。标准库有多个来源,其中之一是STL。它带来了begin,end公约。 std::string早于STL合并到标准库中,并且有大量现有代码使用.substr(pos,length)

+0

...我想如果我们现在正在设计库,'std :: string'看起来会非常不同。 –

5

一个简单的猜测:

不同的方法,你举有不同的行为,这可能是为什么一些使用迭代器和其他没有。

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

std::vector::eraseSequenceContainer概念的一部分,所以它必须有“通用”的形式,可以在任何类型的容器的工作(你可以使用一个std::vectorposcount,但对于一个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::substrstd::basic_string只有一部分(不像erase这是std::liststd::vector一部分,...),并返回一个std::basic_string (不迭代器,你会用一个迭代器在这里做?)。

,我们在std::basic_string其他“非通用”(即,不属于由一些概念强制的)的方法,通常是整个家庭的find方法,insert具有size_typeappend,等等上的过载。

在一个主观的看法,我认为这是最好有一个std::basic_string不表现得像其他容器,因为它不是(我不知道的是,标准要求std::basic_string是一个SequenceContainer或任何类似的)。

,因为你想要一个新的std::basic_string这里不能返回迭代器,所以你将有一个方法采取迭代器返回,但一个对象......我会觉得这更令人不安的比有pos/count,而不是first/last

1

我不能说为什么,我不在场,但对于你错过了[开始,结束)约定范围内的构造。

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