const and non-const string iterators

O

Old Wolf

Hi all. G++ fails to compile the following:

#include <string>

int main()
{
std::string foo("abc=123");
std::string::const_iterator delimiter
= std::find(foo.begin(), foo.end(), '=');

std::string left (foo.begin(), delimiter);
}

The construction of 'left' fails, saying that there's no matching
constructor. The problem appears to be that it is searching
for a constructor taking (iterator, const_iterator) and finds
none. Is this conforming behaviour?

The following change doesn't fix it:

std::string::const_iterator
begin = foo.begin(),
delimiter = std::find(begin, foo.end(), '=');
std::string left (begin, delimiter);

Now it complains that there's no match for std::find() for
the same reason. The following does compile correctly:

std::string::const_iterator
begin = foo.begin(),
end = foo.end(),
delimiter = std::find(begin, end, '=');
std::string left (begin, delimiter);

I thought that non-const iterators should be implicitly
converted to const ones, or that the version of begin()
that returns a const_iterator should be found when it's
trying to find a matching call to std::find().
BCC has no problem with the code.
 
T

Thierry Miceli

Old Wolf said:
Hi all. G++ fails to compile the following:

#include <string>

int main()
{
std::string foo("abc=123");
std::string::const_iterator delimiter
= std::find(foo.begin(), foo.end(), '=');

std::string left (foo.begin(), delimiter);
}

The construction of 'left' fails, saying that there's no matching
constructor. The problem appears to be that it is searching
for a constructor taking (iterator, const_iterator) and finds
none. Is this conforming behaviour?

Yes.
The function template you are trying to instanciate has the following
declaration:

template <class InputIterator >
basic_string(
InputIterator _First,
InputIterator _Last,
const allocator_type& _Al = Allocator ( )
);

You can see that the type of the first and second parameters of the function
template correspond to the same type. The compiler cannot deduce that it is
this constructor that you want to call if your call has a combination of
string::const_iterator and string::iterator as arguments.
The following change doesn't fix it:

std::string::const_iterator
begin = foo.begin(),
delimiter = std::find(begin, foo.end(), '=');
std::string left (begin, delimiter);

Now it complains that there's no match for std::find() for
the same reason.

Same problem here. The general find function is declared as:

template<class InputIterator, class Type>
InputIterator find(
InputIterator _First,
InputIterator _Last,
const Type& _Val
);

Again _First and _Last must have the same type.

The following does compile correctly:

std::string::const_iterator
begin = foo.begin(),
end = foo.end(),
delimiter = std::find(begin, end, '=');
std::string left (begin, delimiter);

I thought that non-const iterators should be implicitly
converted to const ones, or that the version of begin()
that returns a const_iterator should be found when it's
trying to find a matching call to std::find().
BCC has no problem with the code.
There is no type conversion for the instanciation of function templates. A
template type parameter (e.g. InputIterator) is substituted with the same
type (e.g. string::const_iterator) wherever it appears in the template
definition to generate the template instance.


Regards,

Thierry Miceli
www.ideat-solutions.com
 
G

George Faraj

Well, I compiled your code in VC++ 7.1 and it compiled and worked correctly:

#include <iostream>
#include <string>
#include <algorithm>

using namespace std;

int main()
{
string foo = "abc=123";
string::const_iterator delimiter = std::find(foo.begin(), foo.end(),
'=');
string left(foo.begin(), delimiter);

cout << left << endl;
return 0;
}

Is that a recent version of g++ that you tested it on? I guess VC++ 7.1 just
looks harder for constructors :)
The following change doesn't fix it:

std::string::const_iterator
begin = foo.begin(),
delimiter = std::find(begin, foo.end(), '=');
std::string left (begin, delimiter);

Well, if you want to use that, change:
delimiter = std::find(begin, foo.end(), '='); to:
delimiter = std::find(foo.begin(), foo.end(), '=');

Hope that helps,
George Faraj
 
T

Thierry Miceli

George Faraj said:
Well, I compiled your code in VC++ 7.1 and it compiled and worked
correctly:
It does not compile with Comeau which is one of the best compilers (if not
the best) at implementing the C++ standard.
I get the following error:

line 12: error: no instance of constructor

This code should not compile since string::iterator and
string::const_iterator are different types.
Anybody as an opinion on this? Is VC++ wrong?


Thierry Miceli
www.ideat-solutions.com
 
Joined
Oct 16, 2006
Messages
1
Reaction score
0
Hehe, I was searching for my name in google and this topic came out. I forgot to follow-up on it some time ago. I'm going to do that now, if it even matters anymore.

Comeau is right, VC++ is wrong (not that it's a rare occurrence). basic_string's range constructor does not support different iterator types. This appears to be a special case in VC8, which allows the above mentioned code but rejects the following:

Code:
template <typename T>
void f(T, T)
{
}

int main()
{
     f(10, 10L);
}

saying that the template parameter T is ambiguous: could be int or long. This seems very reasonable, though it struck me as strange that it accepted the call to string's range constructor with different iterator types.

I decided to investigate a little more, and realized that VC8's stdlib implementation defines two additional constructors for basic_string. They are:

Code:
basic_string(const_pointer, const_pointer)
basic_string(const_iterator, const_iterator)

These non-standard constructors are the ones allowing the mentioned code compile in VC8. It would probably be wise to consider adding these constructors to the standard, though.

Just to clarify, the code in question is malformed according to the standard. To make it compile, you would explicitly construct a const_iterator:

Code:
string left(string::const_iterator(foo.begin()), delimiter);

Hope that helps whoever still reads this stuff,
George Faraj
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,050
Latest member
AngelS122

Latest Threads

Top