Why is this code complaining about constness?

  • Thread starter markscottwright
  • Start date
M

markscottwright

I'm using visual studio 8, and the following code is failing. For the
life of me, I can't see what's wrong...

void myTest(std::string const& in)
{
using namespace std;
string::const_iterator lastNonWhitespace = find_if(in.rbegin(),
in.rend(), not1(ptr_fun(isspace)));
}

The error is:
strutils.cpp|226 error 2440| 'initializing' : cannot convert from
'std::reverse_iterator<_RanIt>' to
'std::_String_const_iterator<_Elem,_Traits,_Alloc>'
|| with
|| [
||
_RanIt=std::_String_const_iterator<char,std::char_traits<char>,std::allocator<char>>
|| ]
|| and
|| [
|| _Elem=char,
|| _Traits=std::char_traits<char>,
|| _Alloc=std::allocator<char>
|| ]
|| No constructor could take the source type, or constructor
overload resolution was ambiguous
 
V

Victor Bazarov

markscottwright said:
I'm using visual studio 8, and the following code is failing. For the
life of me, I can't see what's wrong...

void myTest(std::string const& in)
{
using namespace std;
string::const_iterator lastNonWhitespace = find_if(in.rbegin(),

Did you mean to declare it 'string::const_reverse_iterator'? If
not, you might want to look into the 'base' member, as in

string::const_iterator lastNonWhitspace = find_if(...) . base();
in.rend(), not1(ptr_fun(isspace)));
}

The error is:
strutils.cpp|226 error 2440| 'initializing' : cannot convert from
'std::reverse_iterator said:
_RanIt=std::_String_const_iterator said:
]
and
[
_Elem=char,
_Traits=std::char_traits<char>,
_Alloc=std::allocator<char>
]
No constructor could take the source type, or constructor
overload resolution was ambiguous
 
B

Bo Persson

markscottwright wrote:
:: I'm using visual studio 8, and the following code is failing. For
:: the life of me, I can't see what's wrong...
::
:: void myTest(std::string const& in)
:: {
:: using namespace std;
:: string::const_iterator lastNonWhitespace = find_if(in.rbegin(),
:: in.rend(), not1(ptr_fun(isspace)));
:: }
::
:: The error is:
:: strutils.cpp|226 error 2440| 'initializing' : cannot convert from
:: 'std::reverse_iterator<_RanIt>' to
:: 'std::_String_const_iterator<_Elem,_Traits,_Alloc>'

It says it all right here -- rbegin() returns a reverse_iterator (and
so will find_if), which cannot be assigned to a const_iterator. They
are just different types, with no conversion defined.

Have you looked into std::string's member functions find_first_of,
find_last_not_of, etc?


Bo Persson
 
M

markscottwright

markscottwright said:
I'm using visual studio 8, and the following code is failing. For the
life of me, I can't see what's wrong...
void myTest(std::string const& in)
{
using namespace std;
string::const_iterator lastNonWhitespace = find_if(in.rbegin(),

Did you mean to declare it 'string::const_reverse_iterator'? If
not, you might want to look into the 'base' member, as in

string::const_iterator lastNonWhitspace = find_if(...) . base();


in.rend(), not1(ptr_fun(isspace)));
}
The error is:
strutils.cpp|226 error 2440| 'initializing' : cannot convert from
'std::reverse_iterator said:
_RanIt=std::_String_const_iterator said:
]
and
[
_Elem=char,
_Traits=std::char_traits<char>,
_Alloc=std::allocator<char>
]
No constructor could take the source type, or constructor
overload resolution was ambiguous

Thanks - that was indeed my problem. I needed to take the resulting
reverse_iterator and get its iterator through the base() method.
Thanks for the help.

Mark
 
J

James Kanze

I'm using visual studio 8, and the following code is failing. For the
life of me, I can't see what's wrong...
void myTest(std::string const& in)
{
using namespace std;
string::const_iterator lastNonWhitespace = find_if(in.rbegin(),
in.rend(), not1(ptr_fun(isspace)));

Victor has pointed out one of the errors. But the last argument
to find_if can't be correct either. First, of course, because
one of the isspace functions is a template, so argument type
deduction fails if it is visible. (Of course, the one that it a
template takes two arguments, so can't be used here. But the
compiler can't know that until it's instantiated the template,
and it can't instantiate the template until it has chosen the
correct isspace.) And secondly, because calling the one
argument version of isspace (from <cctype> or <ctype.h>) with
the char resulting from the referencing of
std::string::const_reverse_iterator is undefined behavior.
 
M

markscottwright

Victor has pointed out one of the errors. But the last argument
to find_if can't be correct either. First, of course, because
one of the isspace functions is a template, so argument type
deduction fails if it is visible. (Of course, the one that it a
template takes two arguments, so can't be used here. But the
compiler can't know that until it's instantiated the template,
and it can't instantiate the template until it has chosen the
correct isspace.) And secondly, because calling the one
argument version of isspace (from <cctype> or <ctype.h>) with
the char resulting from the referencing of
std::string::const_reverse_iterator is undefined behavior.


--
James Kanze (GABI Software) email:[email protected]
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

C++. Sigh.

So, what *is* the correct way to find the last non-whitespace
character in a string?
 
B

BobR

markscottwright said:
So, what *is* the correct way to find the last non-whitespace
character in a string?

std::string test271("hello, my name is mud! ");
size_t indx( test271.find_last_not_of( ' ' ) );
if( indx != test271.npos ){
cout<<"indx="<<indx<<std::endl;
cout<<"test271.substr(indx)="
<<test271.substr(indx)<<std::endl;
cout<<"test271.at( indx )="
<<test271.at( indx )<<std::endl;
} // if()

/* -out-
indx=21
test271.substr(indx)=! // which is "! ".
test271.at( indx )=!
*/

That just finds a 'space' char.
Look up the other overloads of std::string find*** for more.

http://www.dinkumware.com/manuals/.
 
J

James Kanze

C++. Sigh.

Don't blame C++ for this one. We just inherited it from C:).
So, what *is* the correct way to find the last non-whitespace
character in a string?

As usual, there is no one correct way. A lot depends on
context. I do a fair amount of text processing from time to
time, so I've written library classes to wrap the functions in
<locale>, particularly those in the ctype facet. For a one time
use, however, that's a lot more than you'd probably want to
type; if internationalization isn't an issue (or if you're happy
to always use the global locale), then just writting something
like:

struct IsWhite
{
bool operator()( char ch ) const
{
return isspace( static_cast< unsigned char >( ch ) ) ;
}
} ;

and using it as your predicate (possibly with std::not1), should
be largely sufficient.

Officially, of course, you're supposed to use the std::ctype
facet defined in <local>. But everything in <local> is pretty
much a horror with regards to ease of use, so unless you really
need full internationalization, something like the above is much
simpler, and just as good. Just remember to cast any char to
unsigned char before invoking any function in
<ctype.h>/<cctype>, and you should be OK.

And also: be wary of passing the address of a function to a
template function (e.g. as predicate or functional object).
Type deduction and function overload resolution don't always
work very well in such cases: basically, type deduction needs to
know the results of function overload resolution, and vice
versa, so the compiler gives up, and says ambiguous. This is
especially true in cases like the above, because the overloaded
functions are found in <locale>, which may or may not be
indirectly included. It's a bit of a pain to have to write
small classes like the above, but it avoids problems in the long
run.
 

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,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top