我目前有這個比較器函式,它使用 qsort 對自定義結構進行排序,我想將它移植到 std::sort,但它似乎需要回傳一個布林值而不是 -1、0 和 1,我將如何重寫它?
int tsort = 1, sorta = 1;
static auto titleSort(const void *c1, const void *c2) -> int {
switch (tsort) {
case 0:
return ((Title *) c1)->listID - ((Title *) c2)->listID;
case 1:
return strcmp(((Title *) c1)->shortName, ((Title *) c2)->shortName) * sorta;
case 2:
if (((Title *) c1)->isTitleOnUSB == ((Title *) c2)->isTitleOnUSB)
return 0;
if (((Title *) c1)->isTitleOnUSB)
return -1 * sorta;
if (((Title *) c2)->isTitleOnUSB)
return 1 * sorta;
return 0;
case 3:
if (((Title *) c1)->isTitleOnUSB && !((Title *) c2)->isTitleOnUSB)
return -1 * sorta;
if (!((Title *) c1)->isTitleOnUSB && ((Title *) c2)->isTitleOnUSB)
return 1 * sorta;
return strcmp(((Title *) c1)->shortName, ((Title *) c2)->shortName) * sorta;
default:
return 0;
}
}
uj5u.com熱心網友回復:
正如評論中提到的,簡單、快速和骯臟的解決方案是
std::sort(first,last, [](const auto& a,const auto& b) {
return titleSort(&a,&b) < 0;
});
因為比較器std::sort應該true在何時回傳a < b,false否則回傳。當然a < b后titleSort回傳-1或以0其他1方式回傳。因此,您想要映射1到trueand0和1to false,并且< 0這樣做。
您還需要考慮比較器std::sort必須符合命名要求Compare。典型的比較是這樣做的,但是當它們不使用它們時,它們std::sort是未定義的。我沒有找到類似的要求qsort。
uj5u.com熱心網友回復:
如果可能,擺脫int tsort = 1, sorta = 1;
并直接使用適當的方法。
如果需要,可以使用 (C 20) 之類的方式進行調度:
void sortTitle(std::vector<Title>& title, int tsort = 1, sorta = 1)
{
switch (tsort)
{
case 0:
std::ranges::sort(titles, std::ranges::less{}, &Title::listID); break;
case 1: {
const auto proj = [](const Title& title){
return std::string_view(title.shortName);
};
if (sorta == 1) {
std::ranges::sort(titles, std::ranges::less{}, proj);
} else {
std::ranges::sort(titles, std::ranges::greater{}, proj);
}
break;
}
case 2:
if (sorta == 1) {
std::ranges::sort(titles, std::ranges::less{}, &Title::isTitleOnUSB);
} else {
std::ranges::sort(titles, std::ranges::greater{}, &Title::isTitleOnUSB);
}
break;
case 3: {
const auto proj = [](const Title& title){
return std::make_tuple(title.isTitleOnUSB,
std::string_view(title.shortName));
};
if (sorta == 1) {
std::ranges::sort(titles, std::ranges::less{}, proj);
} else {
std::ranges::sort(titles, std::ranges::greater{}, proj);
}
break;
}
}
}
uj5u.com熱心網友回復:
務實的方法有很多好處。例如,您不需要進行太多更改。
但是,舊版本對和值titleSort進行了大量運行時檢查。如果可以僅檢查一次運行時值(在運行時),那會更好。tsortsorta
您可以創建一個仿函式模板,您可以將其實體tsort化為sorta模板引數。如果您想像以前一樣將所有邏輯保留在一個地方,您可以使用constexpr-if進行選擇:
enum class tsort_t { zero, one, two, three };
template <tsort_t tsort, bool sorta = false>
struct titleSorter {
bool operator()(const Title& a, const Title& b) const {
if constexpr (tsort == tsort_t::zero) {
return b.listID < a.listID;
} else if constexpr (tsort == tsort_t::one) {
return std::strcmp(a.shortName, b.shortName) < 0;
} else if constexpr (tsort == tsort_t::two) {
if (a.isTitleOnUSB == b.isTitleOnUSB) return false;
if constexpr (sorta) {
return a.isTitleOnUSB;
} else {
return b.isTitleOnUSB;
}
} else if constexpr (tsort == tsort_t::three) {
if (a.isTitleOnUSB != b.isTitleOnUSB) {
if constexpr (sorta) {
return a.isTitleOnUSB;
} else {
return b.isTitleOnUSB;
}
} else {
return strcmp(a.shortName, b.shortName) < 0;
}
}
}
};
免責宣告:我在轉換邏輯時可能犯了一些錯誤,但我認為沒關系 - 請仔細檢查
為了檢查 and 的運行時值tsort,sorta您將添加一個實體化正確的前端titleSorter:
template <class It>
void titleSort(It first, It last, int tsort, int sorta) {
switch (tsort) {
case 0:
std::sort(first, last, titleSorter<tsort_t::zero>{});
break;
case 1:
if (sorta == 1)
std::sort(first, last, titleSorter<tsort_t::one, true>{});
else
std::sort(first, last, titleSorter<tsort_t::one>{});
break;
case 2:
if (sorta == 1)
std::sort(first, last, titleSorter<tsort_t::two, true>{});
else
std::sort(first, last, titleSorter<tsort_t::two>{});
break;
case 3:
if (sorta == 1)
std::sort(first, last, titleSorter<tsort_t::three, true>{});
else
std::sort(first, last, titleSorter<tsort_t::three>{});
break;
default:
throw std::runtime_error("erroneous tsort algorithm selected");
}
}
演示
注意:我也會考慮更改shortName為std::string.
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/493787.html
上一篇:C 為什么我不能拋出一個抽象類?
下一篇:關于std::istream&運算子實作的問題>>(std::istream&is,icmp_header&header)
