const and non-const string iterators

Discussion in 'C++' started by Old Wolf, Apr 6, 2005.

  1. Old Wolf

    Old Wolf Guest

    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.
    Old Wolf, Apr 6, 2005
    #1
    1. Advertising

  2. "Old Wolf" <> wrote in message
    news:...
    > 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
    Thierry Miceli, Apr 6, 2005
    #2
    1. Advertising

  3. Old Wolf

    George Faraj Guest

    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



    "Old Wolf" <> wrote in message
    news:...
    > 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.
    >
    George Faraj, Apr 6, 2005
    #3
  4. "George Faraj" <> wrote in message
    news:d305ud$6jr$...
    > 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
    Thierry Miceli, Apr 6, 2005
    #4
  5. Old Wolf

    gfaraj

    Joined:
    Oct 16, 2006
    Messages:
    1
    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
    gfaraj, Oct 16, 2006
    #5
    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. Mark Stijnman
    Replies:
    2
    Views:
    466
    =?ISO-8859-15?Q?Juli=E1n?= Albo
    Apr 22, 2005
  2. Marcin Kaliciñski

    Iterators and reverse iterators

    Marcin Kaliciñski, May 8, 2005, in forum: C++
    Replies:
    1
    Views:
    476
    Kai-Uwe Bux
    May 8, 2005
  3. Javier
    Replies:
    2
    Views:
    544
    James Kanze
    Sep 4, 2007
  4. fungus
    Replies:
    13
    Views:
    873
    fungus
    Oct 31, 2008
  5. , India
    Replies:
    10
    Views:
    1,060
    James Kanze
    Aug 8, 2009
Loading...

Share This Page