Search code examples
c++algorithmdictionarymultimap

Having a hard time using max_element (min_element also) on a multimap<Class object, enum>


I'm having a really hard time solving this problem. I want to find the max and min of my keys in my multimap (which happen to be objects of a class). By max and min I'm referring to my objects size member ONLY. I've made a comparator function, to pass it on the max_element(respectively min_element) functions, but I'm getting some error -- invalid initialization of reference of type 'const CFile&' from expression of type 'std::pair < const CFile, CDirectory::Filetype>'

I fixed this problem with my own implementation of min and max functions, but it just doesn't seem right to me. That's why I want to use the min/max_element algorithms...

Here is my sample program::

class CFile {
    string m_strFile;
    unsigned int m_size;
public:
    CFile () { m_strFile = ""; m_size = 0; }
    CFile (string name, int size ) { m_strFile = name; m_size = size; }
    string getFileName () const { return m_strFile; }
    int getFileSize () const { return m_size; }
    void setFileSize ( int size ) { m_size = size; }
    /* stream manipulating and overloading operators here */
static bool Greater(const CFile& obj1, const CFile& obj2) {
        return (obj1.getFileSize() > obj2.getFileSize());
}

bool operator< (CFile obj1, CFile obj2) {
    return obj1.getFileName()<obj2.getFileName();
}


class CDirectory {
    string m_strDirectory;
    enum class Filetype {
        Archive, Hidden, ReadOnly, System, FileNotSupported
    };
    Filetype filetype;
    multimap <CFile, Filetype> m_DirectoryMap;
public:
    friend std::ostream& operator<<(std::ostream& os, Filetype const type)
    {
        switch (type)
        {
        case Filetype::Archive:
            os << "archive";
            break;
        case Filetype::Hidden:
            os << "hidden";
            break;
        case Filetype::ReadOnly:
            os << "read-only";
            break;
        case Filetype::System:
            os << "system";
            break;
        case Filetype::FileNotSupported:
            os << "not-supported";
            break;
        }
        return os;
    }
    CDirectory (string n) {
              fp.open (n, ios::in);
              string dirName, fileName,  fType;
              int fileSize;
              fp >> dirName;
              m_strDirectory = dirName;
              while (fp >> fileName >> fileSize >> fType) {
                      CFile obj (fileName, fileSize);
                       if (fType == "Archive")
                  filetype = Filetype::Archive;
              else if (fType == "Hidden")
                  filetype = Filetype::Hidden;
              else if (fType == "ReadOnly")
                  filetype = Filetype::ReadOnly;
              else if (fType == "System")
                  filetype = Filetype::System;
              else
                  filetype = Filetype::FileNotSupported;
              m_DirectoryMap.insert(pair<CFile, Filetype>(CFile(obj.getFileName(), obj.getFileSize()), Filetype(filetype)));
              }
              multimap<CFile, Filetype>::iterator p = m_DirectoryMap.begin();
              while ( p != m_DirectoryMap.end()) {
                cout << endl << p->first.getFileName() << '\t' << p->first.getFileSize() << '\t' << p->second << endl;
                ++p;
              }
    }
    void test() {
        std::multimap<CFile, Filetype>::iterator result;
        result = std::max_element(m_DirectoryMap.begin(), m_DirectoryMap.end(), Greater);
        std::cout << "max element: " << result->first.GetFileSize() << "\t" << result->first.GetFileName();
    }
};

int main () {
    CDirectory obj("test.txt");
    obj.test();
    return 0;
}

Solution

  • The comapre function for std::max_element needs to have a signature like

    bool cmp(const Type1 &a, const Type2 &b);
    

    Where

    The types Type1 and Type2 must be such that an object of type ForwardIt can be dereferenced and then implicitly converted to both of them. ​

    Since you are using

    std::max_element(m_DirectoryMap.begin(), m_DirectoryMap.end(), Greater);
    

    The type being passed to Greater is *std::multimap<CFile, Filetype>::iterator which is a std::pair < const CFile, CDirectory::Filetype> not a const CFile& obj1 like Greater wants.

    You need to write a function in the that takes two std::pair < const CFile, CDirectory::Filetype> and compares them. A function that should work could look like

    static bool GreaterPair(const std::pair<const CFile, CDirectory::Filetype> & lhs,
                     const std::pair<const CFile, CDirectory::Filetype> & rhs)
    {
        return Greater(lhs.first, rhs.first);
    }
    

    You also have a typo in

    std::cout << "max element: " << result->first.GetFileSize() << "\t" << result->first.GetFileName();
    

    The function is getFileSize() not GetFileSize(). Change it to

    std::cout << "max element: " << result->first.getFileSize() << "\t" << result->first.getFileName();