none
another map RRS feed

  • Question

  • Hi Igor and everyone
    The following program 1 works fine. I was doing some experiment
    so replaced "map<string, vector<NameClass>>MyMap;" in program 1
    with "map<string, set<NameClass>>MyMap;" in program 2. The compiler
    didn't like it and gave me a lengthy error message. Help me out
    please guys.
    Thanks
    Chong

    ********************* Program 1 ******************************
    #include "stdafx.h"

    #include <iostream>
    #include <array>
    #include <vector>
    #include <string>
    #include <map>
    #include <vector>
    using namespace std;

    class NameClass{
     //int age;
     //int k;
    public:
     //int no;
     string name;
     NameClass(string NAME):name(NAME){}
    };

    int main()
    {
     map<string, vector<NameClass>>MyMap;

     MyMap["chong"].push_back(NameClass("Chong Kim"));//ok!

     MyMap["c"].push_back(NameClass("Cxing Kim"));//OK!
     MyMap["c"].push_back(NameClass("Chang Kim"));
     MyMap["c"].push_back(NameClass("Cyang Kim"));

     MyMap["j"].push_back(NameClass("John Kim"));//ok!
     MyMap["j"].push_back(NameClass("Jin Kim"));

     map <string, vector<NameClass>>::iterator it1;
     vector<NameClass>::iterator it2;
       
           for (it1=MyMap.begin();it1!=MyMap.end();it1++){
              cout<<"\n";cout<<(*it1).first<<"=>";  
              for(it2=(*it1).second.begin(); it2!=(*it1).second.end();it2++)
              cout<<(*it2).name.c_str()<<":";
           }
           cout<<"\n";
    }
    /*
    Output:

    c=>Cxing Kim:Chang Kim:Cyang Kim:
    chong=>Chong Kim:
    j=>John Kim:Jin Kim:
    Press any key to continue . . .
    */
    +++++++++++++++++++++++++ Program 2 ++++++++++++++++++++++++++++++

    #include <iostream>
    #include <array>
    #include <vector>
    #include <string>
    #include <map>
    #include <set>
    using namespace std;

    class NameClass{
     //int age;
     //int k;
    public:
     //int no;
     string name;
     NameClass(string NAME):name(NAME){}
    };

    int main()
    {
     map<int, set<NameClass>>MyMap;

     MyMap[0].insert(NameClass("Chong Kim"));//ok!

     MyMap[2].insert(NameClass("Cxing Kim"));//OK!
     MyMap[2].insert(NameClass("Chang Kim"));
     MyMap[2].insert(NameClass("Cyang Kim"));

     MyMap[5].insert(NameClass("John Kim"));//ok!
     MyMap[5].insert(NameClass("Jin Kim"));

     map <int, set<NameClass>>::iterator it1;
     set<NameClass>::iterator it2;//[Q]Is this valid?
       
            for (it1=MyMap.begin();it1!=MyMap.end();it1++){
          cout<<"\n";cout<<it1->first<<"***";  
          for(it2=(*it1).second.begin(); it2!=(*it1).second.end();it2++)
         cout<<(*it2).name.c_str()<<":";
     }
        cout<<"\n";

    }


    Error(s):
    In file included from source_file.cpp:1:
    In file included from /usr/include/c++/v1/iostream:38:
    In file included from /usr/include/c++/v1/ios:216:
    In file included from /usr/include/c++/v1/__locale:15:
    In file included from /usr/include/c++/v1/string:439:
    In file included from /usr/include/c++/v1/algorithm:627:
    In file included from /usr/include/c++/v1/memory:601:
    /usr/include/c++/v1/__functional_base:61:21: error: invalid operands to binary expression ('const NameClass' and 'const NameClass')
            {return __x < __y;}
                    ~~~ ^ ~~~
    /usr/include/c++/v1/__tree:1613:17: note: in instantiation of member function 'std::__1::less<NameClass>::operator()' requested here
                if (value_comp()(__v, __nd->__value_))
                    ^
    /usr/include/c++/v1/__tree:1923:36: note: in instantiation of function template specialization 'std::__1::__tree<NameClass, std::__1::less<NameClass>, std::__1::allocator<NameClass> >::__find_equal<NameClass>' requested here
        __node_base_pointer& __child = __find_equal(__parent, __nd->__value_);
                                       ^
    /usr/include/c++/v1/__tree:1805:32: note: in instantiation of member function 'std::__1::__tree<NameClass, std::__1::less<NameClass>, std::__1::allocator<NameClass> >::__node_insert_unique' requested here
        pair<iterator, bool> __r = __node_insert_unique(__h.get());
                                   ^
    /usr/include/c++/v1/set:570:25: note: in instantiation of function template specialization 'std::__1::__tree<NameClass, std::__1::less<NameClass>, std::__1::allocator<NameClass> >::__insert_unique<NameClass>' requested here
            {return __tree_.__insert_unique(_VSTD::move(__v));}
                            ^
    source_file.cpp:24:11: note: in instantiation of member function 'std::__1::set<NameClass, std::__1::less<NameClass>, std::__1::allocator<NameClass> >::insert' requested here
            MyMap[0].insert(NameClass("Chong Kim"));//ok!
                     ^
    /usr/include/c++/v1/utility:419:1: note: candidate template ignored: could not match 'pair<type-parameter-0-0, type-parameter-0-1>' against 'const NameClass'
    operator< (const pair<_T1,_T2>& __x, const pair<_T1,_T2>& __y)
    ^
    /usr/include/c++/v1/iterator:582:1: note: candidate template ignored: could not match 'reverse_iterator<type-parameter-0-0>' against 'const NameClass'
    operator<(const reverse_iterator<_Iter1>& __x, const reverse_iterator<_Iter2>& __y)
    ^
    /usr/include/c++/v1/iterator:977:1: note: candidate template ignored: could not match 'move_iterator<type-parameter-0-0>' against 'const NameClass'
    operator<(const move_iterator<_Iter1>& __x, const move_iterator<_Iter2>& __y)
    ^
    /usr/include/c++/v1/iterator:1293:1: note: candidate template ignored: could not match '__wrap_iter<type-parameter-0-0>' against 'const NameClass'
    operator<(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT
    ^
    1 error generated.

    Friday, June 19, 2015 8:03 PM

Answers

  • std::set requires its key to be ordered and by default uses std::less to compare keys. In turn std::less attempt to compare the keys using the < operator. And you don't have such an operator for the NameClass, that's what this error is trying to tell you:

    "/usr/include/c++/v1/__functional_base:61:21: error: invalid operands to binary expression ('const NameClass' and 'const NameClass')
            {return __x < __y;}"

    The easiest way to solve this is to add the necessary operator < that simply compares the names:

    bool operator < (const NameClass& x, const NameClass& y) {
        return x.name < y.name;
    }
    

    " set<NameClass>::iterator it2;//[Q]Is this valid?"

    Yes but variables should be declared in the innermost scope they are needed. I'd write that code like this:

    for (map<int, set<NameClass>>::iterator it1 = MyMap.begin(); it1 != MyMap.end(); it1++)
    {
        cout << "\n"; cout << it1->first << "***";
    
        for (set<NameClass>::iterator it2 = (*it1).second.begin(); it2 != (*it1).second.end(); it2++)
            cout << (*it2).name.c_str() << ":";
    }
    

    Or using C++11 features and without some unnecessary stuff (c_str() for example):

    for (const auto &pair : MyMap)
    {
        cout << "\n" << pair.first << "***";
    
        for (const auto &nameClass : pair.second)
            cout << nameClass.name << ":";
    }
    

    Friday, June 19, 2015 8:39 PM
    Moderator
  • On 6/19/2015 4:03 PM, "chong kyong kim" wrote:

    The following program 1 works fine. I was doing some experiment
    so replaced "map<string, vector<NameClass>>MyMap;" in program 1
    with "map<string, set<NameClass>>MyMap;" in program 2.

    Elements of std::set need to be comparable, by default with  less-than `<` operator. Instances of NameClass are not so comparable.


    Igor Tandetnik
    Friday, June 19, 2015 8:52 PM

All replies

  • std::set requires its key to be ordered and by default uses std::less to compare keys. In turn std::less attempt to compare the keys using the < operator. And you don't have such an operator for the NameClass, that's what this error is trying to tell you:

    "/usr/include/c++/v1/__functional_base:61:21: error: invalid operands to binary expression ('const NameClass' and 'const NameClass')
            {return __x < __y;}"

    The easiest way to solve this is to add the necessary operator < that simply compares the names:

    bool operator < (const NameClass& x, const NameClass& y) {
        return x.name < y.name;
    }
    

    " set<NameClass>::iterator it2;//[Q]Is this valid?"

    Yes but variables should be declared in the innermost scope they are needed. I'd write that code like this:

    for (map<int, set<NameClass>>::iterator it1 = MyMap.begin(); it1 != MyMap.end(); it1++)
    {
        cout << "\n"; cout << it1->first << "***";
    
        for (set<NameClass>::iterator it2 = (*it1).second.begin(); it2 != (*it1).second.end(); it2++)
            cout << (*it2).name.c_str() << ":";
    }
    

    Or using C++11 features and without some unnecessary stuff (c_str() for example):

    for (const auto &pair : MyMap)
    {
        cout << "\n" << pair.first << "***";
    
        for (const auto &nameClass : pair.second)
            cout << nameClass.name << ":";
    }
    

    Friday, June 19, 2015 8:39 PM
    Moderator
  • On 6/19/2015 4:03 PM, "chong kyong kim" wrote:

    The following program 1 works fine. I was doing some experiment
    so replaced "map<string, vector<NameClass>>MyMap;" in program 1
    with "map<string, set<NameClass>>MyMap;" in program 2.

    Elements of std::set need to be comparable, by default with  less-than `<` operator. Instances of NameClass are not so comparable.


    Igor Tandetnik
    Friday, June 19, 2015 8:52 PM
  • Hi Mike

    Thanks for your tutorial! It is brilliant!

    Regards

    Chong


    Saturday, June 20, 2015 12:24 AM
  • Hi Igor

    I've got it now. Thanks.

    Regards

    Chong

    Saturday, June 20, 2015 12:40 AM