The following code compile correctly for me in some environments (e.g. on compiler explorer with GCC 9.3.0) and complains in others (CentOS 7.9.2009 (Core), GCC 9.3.1).
#include <iostream>
#include <string>
using namespace std;
int main() {
std::string name="aakash";
name.erase(name.begin() 2, name.cend());
return 0;
}
When I get an error, the error is:
test.cpp:6:40: error: no matching function for call to 'std::basic_string<char>::erase(__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, std::basic_string<char>::const_iterator)'
6 | name.erase(name.begin() 2, name.cend());
| ^
In file included from /opt/rh/devtoolset-9/root/usr/include/c /9/string:55,
from /opt/rh/devtoolset-9/root/usr/include/c /9/bits/locale_classes.h:40,
from /opt/rh/devtoolset-9/root/usr/include/c /9/bits/ios_base.h:41,
from /opt/rh/devtoolset-9/root/usr/include/c /9/ios:42,
from /opt/rh/devtoolset-9/root/usr/include/c /9/ostream:38,
from /opt/rh/devtoolset-9/root/usr/include/c /9/iostream:39,
from test.cpp:1:
/opt/rh/devtoolset-9/root/usr/include/c /9/bits/basic_string.h:4698:7: note: candidate: 'std::basic_string<_CharT, _Traits, _Alloc>& std::basic_string<_CharT, _Traits, _Alloc>::erase(std::basic_string<_CharT, _Traits, _Alloc>::size_type, std::basic_string<_CharT, _Traits, _Alloc>::size_type) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>; std::basic_string<_CharT, _Traits, _Alloc>::size_type = long unsigned int]'
4698 | erase(size_type __pos = 0, size_type __n = npos)
| ^~~~~
/opt/rh/devtoolset-9/root/usr/include/c /9/bits/basic_string.h:4698:23: note: no known conversion for argument 1 from '__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >' to 'std::basic_string<char>::size_type' {aka 'long unsigned int'}
4698 | erase(size_type __pos = 0, size_type __n = npos)
| ~~~~~~~~~~^~~~~~~~~
/opt/rh/devtoolset-9/root/usr/include/c /9/bits/basic_string.h:4714:7: note: candidate: 'std::basic_string<_CharT, _Traits, _Alloc>::iterator std::basic_string<_CharT, _Traits, _Alloc>::erase(std::basic_string<_CharT, _Traits, _Alloc>::iterator) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>; std::basic_string<_CharT, _Traits, _Alloc>::iterator = __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >; typename _Alloc::rebind<_CharT>::other::pointer = char*]'
4714 | erase(iterator __position)
| ^~~~~
/opt/rh/devtoolset-9/root/usr/include/c /9/bits/basic_string.h:4714:7: note: candidate expects 1 argument, 2 provided
/opt/rh/devtoolset-9/root/usr/include/c /9/bits/basic_string.h:4734:7: note: candidate: 'std::basic_string<_CharT, _Traits, _Alloc>::iterator std::basic_string<_CharT, _Traits, _Alloc>::erase(std::basic_string<_CharT, _Traits, _Alloc>::iterator, std::basic_string<_CharT, _Traits, _Alloc>::iterator) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>; std::basic_string<_CharT, _Traits, _Alloc>::iterator = __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >; typename _Alloc::rebind<_CharT>::other::pointer = char*]'
4734 | erase(iterator __first, iterator __last);
| ^~~~~
/opt/rh/devtoolset-9/root/usr/include/c /9/bits/basic_string.h:4734:40: note: no known conversion for argument 2 from '__normal_iterator<const char*,[...]>' to '__normal_iterator<char*,[...]>'
4734 | erase(iterator __first, iterator __last);
| ~~~~~~~~~^~~~~~
| ~~~~~~~~~^~~~~~
The error looks reasonable to me because, as per C documentation, both arguments to std::basic_string::erase
should either be of type iterator
or const_iterator
.
So, when it works (e.g. here), what allows it to work?
CodePudding user response:
Since C 11, both arguments to the two-iterator overload of std::string::erase()
are const_iterator
. See form #3 on this cppreference page (the one you linked in your question).
Further, the C 11 Standard requires that a conatiner's iterator
types are convertible to the equivalent const_iterator
.
From this Draft C 11 Standard, in §23.2.1 [container.requirements.general], Table 96 has the following entry (bold emphasis mine):
Expression | Return Type | Operational Semantics | Assertion/note | … |
---|---|---|---|---|
X::iterator |
iterator type whose value type is T |
any iterator category that meets the forward iterator requirements. convertible to X::const_iterator . |
… |
So, in your call to .erase()
, the first argument is being converted to a string::const_iterator
.
Thus, the bug is in those compilers that don't accept your call, assuming you have set them also to use the C 11 (or later) standard.