CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 2 12 LastLast
Results 1 to 15 of 17
  1. #1
    Join Date
    Oct 2001
    Location
    Brookfield, MO, USA
    Posts
    30

    Question Understanding the map template

    I am attempting to understand how to use the MAP (caps for emphasis) standard template. I have figured out how to create a multimap, and how to add items to it, but I am having difficulty trying to reread the multimap. The map declaration looks like this:

    #include <map>
    #include <string>
    #include <iostream>

    // Using a string object for both the key
    // and the item
    typedef multimap<string, string> NameList;

    typedef NameList::iterator NameIt;

    NameList Names;
    NameIt CurrentName;


    // An example of adding one element
    // to the map:
    string NameA1 = "Patty Anderson";
    string NameA2 = "Anderson";
    Names.insert(NameList::value_type(NameA2, NameA1));

    // This is the code I am trying to use to
    // output the list to the console:

    for(CurrentName = Names.begin(); CurrentName != Names.end(); CurrentName++);
    {
    // Program crashes here.
    cout << (*CurrentName).second << endl;

    }

    When I get to the cout line of code, the program blows up, even though I am practically copying the line from the VC++ example in their help files.

    Can anyone tell me what they think I am doing wrong?

    TIA.

  2. #2
    Join Date
    May 2002
    Location
    Quebec City, Canada
    Posts
    374
    I don't know what's wrong with your code it crashes when I run it here too, but this way of parsing the tree works:

    Code:
    CurrentName = Names.begin();
    while( CurrentName != Names.end() )
    {
         cout << (*CurrentName).second;
         cout << endl;
         ++CurrentName;
    }
    Mystifying.

    Edit:

    Actually, this also works. I don't know what is wrong with the original code, but here's my code that works:

    Code:
    #include <map>
    #include <string>
    #include <iostream>
    
    using namespace std;
     
    // Using a string object for both the key 
    // and the item
    
    typedef multimap<string, string> NameList;
    
    typedef NameList::iterator NameIt;
    
    int main()
    {
    	NameList Names;
    	NameIt CurrentName;
    
    	// An example of adding one element 
    	// to the map:
    	string NameA1 = "Patty Anderson";
    	string NameA2 = "Anderson";
    	Names.insert
    		(NameList::value_type(NameA2, NameA1));
    
    	CurrentName = Names.begin();
    
    	while( CurrentName != Names.end() )
    	{
    		cout << (*CurrentName).second;
    		cout << endl;
    		++CurrentName;
    	}
    
    	for( CurrentName = Names.begin(); CurrentName != Names.end(); CurrentName++ )
    	{
    		cout << (*CurrentName).second;
    		cout << endl;
    	}
    }
    Last edited by proxima centaur; October 10th, 2002 at 09:09 AM.
    Martin Breton
    3D vision software developer and system integrator.

  3. #3
    Join Date
    Oct 2001
    Location
    Brookfield, MO, USA
    Posts
    30

    Talking Re: Using Maps

    Thanks, Centaur. The while loop worked, but strangely enough, the for loop did not. Go figure.

  4. #4
    Join Date
    May 2002
    Location
    Quebec City, Canada
    Posts
    374
    No problem.

    But it really mystifies me as to WHY the for loop sometimes works and sometimes doesn't.

    Anybody can help us on that topic?

    Martin Breton
    3D vision software developer and system integrator.

  5. #5
    Join Date
    Aug 2002
    Location
    VA, USA
    Posts
    137
    Why is there a semi-colon after the for loop in the OP's example?
    Maybe the compiler sees the loop is a no-op and is optimizing the
    loop out of the code completely. This would cause the iterator
    to never get initialized.

    regards, willchop
    Last edited by willchop; October 10th, 2002 at 10:22 AM.

  6. #6
    Join Date
    Oct 2001
    Location
    Brookfield, MO, USA
    Posts
    30

    Angry Making MAP work

    Geez...felled by the stupidest newbie mistake on the books. Yeah, that was the problem. Remove the semi colon and the For loop worked like a charm. Thanks everyone for your help.

  7. #7
    Join Date
    May 2002
    Location
    Quebec City, Canada
    Posts
    374
    Ah!!!!!!!!!!!!!!! thanks willchop !

    I didn't see the friggin' semi-colon! That's why it works on my version of the for loop!

    Don't worry pedantic, we were both as blind as mice! hehehe

    Now I understand what happens. You parse the whole multimap and after the loop, your iterator points to Names.end() which is NOT the last element of the map, but rather a flag to tell the iterator when to stop. When you try to access the data pointed by Names.end(), it is an illegal operation punishable by crash.

    Ok... I feel better now. I thought the compiler was misbehaving.
    Martin Breton
    3D vision software developer and system integrator.

  8. #8
    Join Date
    Oct 2001
    Location
    Brookfield, MO, USA
    Posts
    30

    Unhappy End of all maps

    Though I'll add my thanks to willchop, I have to say that I don't feel particularly better about it...(grin).

  9. #9
    Join Date
    Mar 2002
    Location
    Philadelphia
    Posts
    150

    Question

    Please help STL Gurus. It seemed to me that one could overload the copy function template to copy multimap value seconds to an ostream iterator. But unfortunately, the following doesn't compile. I get the following error for the copy() call below:
    c:\program files\microsoft visual studio\vc98\include\xutility(19) : error C2679: binary '=' : no operator defined which takes a right-hand operand of type 'struct std::pair<class std::basic_string<char,struct std::char_traits<char>,class std::alloc

    Is it possible to do what I am attempting?

    Thanks in advance.
    Regards,
    -Ron

    • //////////////////////////////////////////////////////////
      // multimapfun.cpp
      #include <iostream>
      #include <string>
      #include <map>
      #include <iterator>

      using namespace std;

      typedef multimap<string, string> NameList;

      typedef NameList::iterator NameIt;

      template <NameIt, class OutputIterator>
      OutputIterator copy(NameIt first, NameIt last, OutputIterator result)
      {
      while(first!=last)
      {
      *result++ = (*first++).second();
      }
      return result;
      }

      int main(int argc, char* argv[])
      {
      NameList Names;
      NameIt CurrentName;

      // An example of adding one element
      // to the map:
      string NameA1 = "Patty Anderson";
      string NameA2 = "Anderson";
      Names.insert
      (NameList::value_type(NameA2, NameA1));

      ostream_iterator<string> out(cout, "\n");
      copy(Names.begin(), Names.end(), out); // <- error here
      cout << endl << flush;

      return 0;
      }
      //
      //////////////////////////////////////////////////////////

  10. #10
    Join Date
    Mar 2002
    Location
    Philadelphia
    Posts
    150

    Red face

    ooops. the whole error message is as follows

    c:\program files\microsoft visual studio\vc98\include\xutility(19) : error C2679: binary '=' : no operator defined which takes a right-hand operand of type 'struct std::pair<class std::basic_string<char,struct std::char_traits<char>,class std::alloc
    ator<char> > const ,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >' (or there is no acceptable conversion)
    c:\working\utility\roncreations\cpp\stl\multimapfun\multimapfun.cpp(42) : see reference to function template instantiation 'class std::ostream_iterator<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,c
    har,struct std::char_traits<char> > __cdecl std::copy(class std::_Tree<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,struct std::pair<class std::basic_string<char,struct std::char_traits<char>,class std::all
    ocator<char> > const ,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >,struct std::multimap<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class std::basic_string<char
    ,struct std::char_traits<char>,class std::allocator<char> >,struct std::less<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >,class std::allocator<class std::basic_string<char,struct std::char_traits<char>,cl
    *** std::allocator<char> > > >::_Kfn,struct std::less<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >,class std::allocator<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char
    > > > >::iterator,class std::_Tree<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,struct std::pair<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const ,class std::bas
    ic_string<char,struct std::char_traits<char>,class std::allocator<char> > >,struct std::multimap<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class std::basic_string<char,struct std::char_traits<char>,class
    std::allocator<char> >,struct std::less<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >,class std::allocator<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > >::_Kfn
    ,struct std::less<class std::basic_string<char,struct st
    ::char_traits<char>,class std::allocator<char> > >,class std::allocator<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > >::iterator,class std::ostream_iterator<class std::basic_string<char,struct std::char_t
    raits<char>,class std::allocator<char> >,char,struct std::char_traits<char> >)' being compiled

  11. #11
    Join Date
    Apr 1999
    Posts
    27,449
    Well one potential error is that you may have two versions of "copy" going that are ambiguous. You have the std::copy, and your own template copy function. I would either

    a) call it something else besides copy, or

    b) put the scope resolution ::copy() when you call it, or

    c) put your version of copy in a namespace and prepend your call to copy with the namespace.

    This won't solve your current error, but it is an error that some compilers would have let you know about since the STL headers may include <algorithm> which will include std::copy.

    Regards,

    Paul McKenzie

  12. #12
    Join Date
    Apr 1999
    Posts
    27,449
    Also, another error is here:
    Code:
    // *result++ = (*first++).second(); // Error!!
    *result++ = (*first++).second;  // Correct
    The "second" is not a function call, so remove the parentheses.

    Regards,

    Paul McKenzie

  13. #13
    Join Date
    Mar 2002
    Location
    Philadelphia
    Posts
    150

    Question

    Paul,
    Thanks for your response. I cleaned up the code with the suggestions, but I still get the error described below.
    I can't figure this one out. Does anyone have any ideas?
    Regards,
    -Ron

    <code>
    //////////////////////////////////////////////////////////
    // multimapfun.cpp
    #pragma warning( disable : 4786) // MSVC++ truncates debug information to '255'
    #include <conio.h>
    #include <iostream>
    #include <string>
    #include <map>

    #include <iterator>

    using namespace std;

    typedef multimap<string, string> NameMMap;
    typedef NameMMap::iterator NameMMapIt;

    template <NameMMapIt, class OutputIterator>
    void cpy(NameMMapIt first, NameMMapIt last, OutputIterator result)
    {
    while(first!=last)
    {
    *result++ = (*first++).second;
    }
    return result;
    }

    int main(int argc, char* argv[])
    {
    cout << "Welcome to MultiMap Fun!" << endl << flush;

    NameMMap Names;
    NameMMapIt CurrentName;

    // An example of adding one element
    // to the map:
    string NameA1 = "Patty Anderson";
    string NameA2 = "Anderson";
    Names.insert(NameMMap::value_type(NameA2, NameA1));

    ostream_iterator<string> out(cout, "\n");
    cpy(Names.begin(), Names.end(), out); // <- error C2783 here
    // error C2783: could not deduce template argument for '__formal'
    // A template argument cannot be deduced by the compiler. For example:
    // template<class T1, class T2> T1 f(T2){ }
    // f(1);

    cout << endl << flush;

    cout << "Press any key to end..." << endl << flush;
    _getch();
    return 0;
    }
    </code>

  14. #14
    Join Date
    May 2000
    Location
    Phoenix, AZ [USA]
    Posts
    1,347
    Try the following code changes to your cpy definition:
    Code:
    template <typename NameMMapIt, typename OutputIterator>
    OutputIterator cpy(NameMMapIt first, NameMMapIt last, OutputIterator result)
    {
       while (first!=last)
       {
          *result++ = (*first++).second;
       }
       return result;
    }
    After examining some old points, though, I can't figure out why
    you're not just using std::copy() [granted, I didn't peruse the
    thread TOO intensely].

    Edit: I think you just want to print out the map's values; I think
    you could use for_each and a functor instead of using your own
    version of copy. To each his own

    --Paul
    Last edited by PaulWendt; December 3rd, 2002 at 12:35 PM.

  15. #15
    Join Date
    Mar 2002
    Location
    Philadelphia
    Posts
    150

    Cool thanks

    Thanks Paul.

    Yes, I am learning STL and I appreciate your help. I rewrote std::copy() as a learning exercise. for_each sounds cool.
    It was "typename" that made the difference here:

    template <typename NameMMapIt, typename OutputIterator>

    I didn't know such a keyword existed. But I should have known the following which works as well:
    template <class NameMMapIt, class OutputIterator>

    A good understanding of templates seems predicate to understanding STL. I guess when you are defining a template class or function you must always use typename or class for template parameters. And that it is when you are instantiating, or the compiler automatically instantiates, the template the argument types are passed in to the template. I mixed both ways for my template arguments in my template definition.

    Regards,
    -Ron

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured