Why is this code complaining about constness?

Discussion in 'C++' started by markscottwright, Aug 1, 2007.

  1. 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
     
    markscottwright, Aug 1, 2007
    #1
    1. Advertising

  2. 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(),


    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<_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


    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Aug 1, 2007
    #2
    1. Advertising

  3. markscottwright

    Bo Persson Guest

    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
     
    Bo Persson, Aug 1, 2007
    #3
  4. On Aug 1, 1:36 pm, "Victor Bazarov" <> wrote:
    > 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(),

    >
    > 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<_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

    >
    > --
    > Please remove capital 'A's when replying by e-mail
    > I do not respond to top-posted replies, please don't ask


    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
     
    markscottwright, Aug 1, 2007
    #4
  5. markscottwright

    James Kanze Guest

    On Aug 1, 8:10 pm, 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)));


    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:
    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
     
    James Kanze, Aug 2, 2007
    #5
  6. On Aug 2, 4:23 am, James Kanze <> wrote:
    > On Aug 1, 8:10 pm, 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)));

    >
    > 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:
    > 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?
     
    markscottwright, Aug 2, 2007
    #6
  7. markscottwright

    BobR Guest

    markscottwright <> wrote in message...

    >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/.

    --
    Bob R
    POVrookie
     
    BobR, Aug 2, 2007
    #7
  8. markscottwright

    James Kanze Guest

    On Aug 2, 9:30 pm, markscottwright <> wrote:
    > On Aug 2, 4:23 am, James Kanze <> wrote:
    > > On Aug 1, 8:10 pm, 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)));


    > > 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.


    > > > }


    > 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.

    --
    James Kanze (GABI Software) email:
    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
     
    James Kanze, Aug 3, 2007
    #8
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. codehead
    Replies:
    3
    Views:
    410
    codehead
    Jun 13, 2005
  2. Replies:
    2
    Views:
    440
  3. Mr. SweatyFinger
    Replies:
    2
    Views:
    1,990
    Smokey Grindel
    Dec 2, 2006
  4. Replies:
    6
    Views:
    476
  5. Replies:
    14
    Views:
    829
    Ian Collins
    Apr 4, 2006
Loading...

Share This Page