【问题标题】:qsort of a structure in c++c++中结构的qsort
【发布时间】:2015-04-07 08:33:16
【问题描述】:

我尝试对结构进行排序,但出现此错误:

    error: cannot convert ‘std::vector<Node>’ to ‘void*’ for argument ‘1’ to ‘void qsort(void*, size_t, size_t, __compar_fn_t)’
  qsort(nodes,nodes.size(), sizeof(Node), dataClustering::compare);

这是我的代码: 比较函数:

int compare(const void * node1, const void * node2){
    string name1 = ((const struct Node*)node1)->name;
    string name2 = ((const struct Node*)node2)->name;
    int start1 = ((const struct Node*)node1)->start;
    int start2 = ((const struct Node*)node2)->start;

    if(name1 <= name2 && start1 <= start2){
        return -1;
    }
    else if(name1 > name2 && start1 > start2){
        return 1;
    }
    else{
        return 0;
    }       
}

在另一个函数中调用比较:

qsort(allNodes,allNodes.size(), sizeof(Node), compare);

以及 .hpp 文件中的标头(我尝试将其放在静态中,但这并不能解决错误):

int compare(struct Node *, struct Node *);

【问题讨论】:

  • TL;DR C++ 不支持指针隐式转换到/fom void *
  • 听你的编译器:allNodes 不是void*
  • 为什么你想这样做,而不是更理智的std::sort(begin(nodes), end(nodes))
  • @user3608663 那么为什么不使用std::sort(begin(nodes), end(nodes), compare_functor)呢?
  • 永远不要在 C++ 中使用qsort。如果您不知道如何使用std::sort 来满足您的目的,请询问如何使用std::sort,而不是如何使用qsort

标签: c++ struct qsort


【解决方案1】:

您可以将向量传递给 C 风格的排序,例如,像这样:

qsort(&allNodes[0], allNodes.size(), sizeof(Node), compare);

你最好使用std::sort,它本身就适用于向量:

bool compareNodes(const Node& lhs, const Node& rhs) {
    return (lhs.name < rhs.name)
        || (lhs.name == rhs.name && lhs.start < rhs.start);
}
...
std::sort(allNodes.begin(), allNodes.end(), compareNodes);

在 C++11/C++14 中,您也可以将比较定义为 lambda:

std::sort(allNodes.begin(), allNodes.end(), [] (const auto& lhs, const auto& rhs) {
    return (lhs.name < rhs.name)
        || (lhs.name == rhs.name && lhs.start < rhs.start);
});

(上面的代码使用 auto 作为 lambda 参数,这是 C++14 的一个特性)。

【讨论】:

  • 我认为allNodes.data()&amp;allNodes[0] 更可取?无论如何,我想最终都是一样的。
  • s/C++11/C++14; lambda 参数的 auto 来自 C++14。
  • 谢谢!我做到了,它正在工作。我还有一个错误,我在一个类中声明 compareNode 并且它不起作用......现在没关系,谢谢
  • 与其重新发明比较算法,还可以使用std::tie(lhs.name, lhs.start) &lt; std::tie(rhs.name, rhs.start)
【解决方案2】:

错误是你

cannot convert ‘std::vector<Node>’ to ‘void*’

因此,std::vector&lt;Node&gt; 不可能是像 qsort 这样带有签名的函数的合适的第一个参数

void (void*, size_t, size_t, __compar_fn_t)

虽然您可以在此处使用 qsort,但实际上不应该:您应该使用 C++ 标准库中的 std::sort

using std::sort;
sort(begin(allNodes), end(allNodes), compare_function);

这里,compare_function 应该是一个函数,其行为类似于 &lt; 并接受两个适当类型的参数(例如,您正在排序的对象的实际类型或 const 对它们的引用,而不是指向它们的指针或void 指针),如果第一个参数小于第二个参数,则返回bool。 (compare_function 实际上不一定是函数:它也可以是任何具有适当的 operator() 或 lambda 的对象)

【讨论】:

  • 我认为你不需要那个using 声明; ADL 已经找到了正确的名称。
  • @Kerrek:在这种特殊情况下你不会,但在其他一些情况下你会(例如,使用默认比较对 C 样式数组进行排序),所以我认为值得发布一般模式.
  • 感谢您的回答
【解决方案3】:

如果您只想排序,请使用

#include <algorithm>
...
bool myfunction (const Node &lhs, const Node &lhs) {
  if(lhs.name < rhs.name) return true;
  return (lhs.name == rhs.name && lhs.start < rhs.start));
}
...
std::sort(allNodes.begin(), allNodes.end(), compare_func);

进一步阅读:std::sort

如果你想使用 cstyle qsort(我建议你不应该这样做),添加一个包装函数将void * 转换为Node * 并将qsort 的第一个参数更改为static_cast&lt;void *&gt;(&amp;allNodes[0])

【讨论】:

  • 如果你想用cstyleqsort,就用力拍自己的手腕吧。在这里,FTFY。
  • @n.m.你的建议好多了
  • 还要注意 std::sort 比 C qsort 快。 (由于例如比较操作的编译时绑定等)。
  • 我会写myfunction: return std::tie(lhs.name, lhs.start) &lt; std::tie(rhs.name, rhs.start);
  • 感谢您的建议
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多