【问题标题】:Having a hard time using max_element (min_element also) on a multimap<Class object, enum>在 multimap<Class object, enum> 上使用 max_element (也有 min_element)很难
【发布时间】:2016-05-20 21:52:29
【问题描述】:

我很难解决这个问题。我想在我的多图(恰好是一个类的对象)中找到我的键的最大值和最小值。最大和最小我仅指我的对象大小成员。我已经制作了一个比较器函数,将它传递给 max_element(分别为 min_element)函数,但我遇到了一些错误——invalid initialization of type of reference of type 'const CFile&' from expression of type'std::对 '

我用自己实现的 min 和 max 函数解决了这个问题,但它对我来说似乎不合适。这就是为什么我想使用 min/max_element 算法......

这是我的示例程序::

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;
}

【问题讨论】:

  • 您能否将示例简化为minimal reproducible example?注意“最小”部分。文件输入、流操纵器等与您描述的问题几乎没有关系。
  • 不相关的注释:为一个类定义两个(不一致的!)运算符&lt;(一个在命名空间范围内,一个在类中)是可怕的做法,并且等待灾难即将发生。摆脱其中一个(或两者,甚至;comapring files for ordering 是相当不直观的)。
  • 谢谢,我会编辑我原来的帖子。我有全局运算符&lt;,因为(不知何故)如果我没有它,我似乎无法插入我的多映射对(来自我的第二类构造函数)。
  • 如果您同时删除它们,则必须为地图提供合适的比较器。顺便说一句,课堂内&lt; 的问题可能是它不是const,因此不能用于地图的键(即const)。
  • 是的,这似乎是问题所在...我将其设为 const 并删除了全局变量 - 现在一切都很好。 :) 谢谢!

标签: c++ algorithm dictionary multimap


【解决方案1】:

std::max_element 的comapre 函数需要有一个类似的签名

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

在哪里

Type1Type2 类型必须使得 ForwardIt 类型的对象可以被取消引用,然后隐式转换为它们。 ​

因为你正在使用

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

传递给Greater 的类型是*std::multimap&lt;CFile, Filetype&gt;::iterator,它是std::pair &lt; const CFile, CDirectory::Filetype&gt; 而不是const CFile&amp; obj1,就像Greater 想要的那样。

你需要编写一个函数来接受两个std::pair &lt; const CFile, CDirectory::Filetype&gt; 并比较它们。一个应该可以工作的函数可能看起来像

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);
}

你也有错别字

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

函数是getFileSize() 而不是GetFileSize()。改成

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

【讨论】:

  • 感谢您的帮助。当我尝试使用作为 comp 传递的 GreaterPair 调用 max_element 时,我得到一些 `no matching function for call to 'max_element(std::multimap::iterator, std::multimap::iterator, )'`。对此有什么想法吗? :(
  • @hopittyhop 我忘记了 static 关键字。试试看。
  • 现在它通过了那条线。但是我在打印最大元素的那一行遇到了另一个错误。这是我的 test() 函数的第三行。错误:“const class CFile”没有名为“GetFileSize”的成员。 result 不是一对有 2 个 CFile 类的对象吗?
  • @hopittyhop 我忘了提。你有一个错字。我将其添加到答案中。
  • @hopittyhop 没问题
【解决方案2】:

min_element / max_element 在容器上运行并且不支持地图。他们将遍历所有元素并找到您正在寻找的元素。问题是当你有一个多重映射时,元素类型是pair&lt;const CFile, FileType&gt; 而不仅仅是CFile。只需修改您的 Greater 函数以使用该对,并返回比较该对中的 CFile 的结果。

如果您想要更通用/更短的解决方案,您可以为 std::multimap&lt;Cfile, FileType&gt;::value_type 定义一个别名,这将是我提到的这对。

应该是这样的

static bool Greater(const std::pair<const CFile, FileType>& a,
                    const std::pair<const CFile, FileType>& b) {
    return (a.first.getFileSize() > b.first.getFileSize());
}

【讨论】:

  • Greater 的修改版本(比较一对 CFile 大小成员)会是什么样子?我不知道。 :(
【解决方案3】:

在循环中使用 multimap::upper_bound 应该更有效。

【讨论】:

  • 使用比较函数来比较多图中的对象不是最好的方法吗?
  • 比较功能是对任何地图/多地图中的键进行排序所必需的。所以如果你有一个地图/多地图,你已经有一个比较功能。
  • 但是,例如,我可以按 fileName 对多图对进行排序,并使用一些返回 min 和 max 的函数(我通过比较函数通过 fileSize 进行比较?
  • 啊哈,现在我明白了 - 你的地图是由 CFile
猜你喜欢
  • 1970-01-01
  • 2015-02-24
  • 1970-01-01
  • 2018-05-25
  • 1970-01-01
  • 1970-01-01
  • 2012-04-26
  • 1970-01-01
  • 2017-07-16
相关资源
最近更新 更多