我在std::optionals的结构中有一个结构,我试图找到结构中的最小值和最大值。然而,使用std::minmax_element似乎不准确,我不得不拆分比较函数,转而使用std::min_element和std::max_element。有没有一种方法可以让我仍然使用std::minmax_element并且更干净?
#include <iostream>
#include <vector>
#include <optional>
#include <algorithm>
struct AE
{
double A;
double E;
};
struct HM
{
std::optional<AE> H;
std::optional<AE> M;
};
bool CompareHM(const HM& a_, const HM& b_)
{
// If both H fields have a value, compare them by A
if (a_.H.has_value() && b_.H.has_value())
{
return a_.H->A < b_.H->A;
}
// If only one H field has a value, set to false
else
{
return false;
}
}
bool CompareHMMax(const HM& a_, const HM& b_)
{
// If both H fields have a value, compare them by A
if (a_.H.has_value() && b_.H.has_value())
{
return a_.H->A < b_.H->A;
}
// If only one H field has a value, consider it larger
else if (a_.H.has_value())
{
return false;
}
// If both H fields are empty, or if just b has a value
else {
return false;
}
}
bool CompareHMMin(const HM& a_, const HM& b_)
{
// If both H fields have a value, compare them by A
if (a_.H.has_value() && b_.H.has_value())
{
return a_.H->A < b_.H->A;
}
// If only one H field has a value, consider it smaller
else if (a_.H.has_value())
{
return true;
}
// If both H fields are empty, or if just b has a value
else
{
return false;
}
}
int main()
{
// Create a vector of HM structs with some data
std::vector<HM> vec = {
HM{AE{1.8, 4.5}, AE{7.2, 4.1}},
HM{AE{2.3, 3.4}, std::nullopt},
HM{std::nullopt, AE{6.7, 8.9}},
HM{AE{0.9, 2.1}, std::nullopt},
HM{AE{1.8, 4.2}, AE{7.6, 9.0}},
HM{std::nullopt, AE{0.7, 13.5}},
HM{std::nullopt, AE{0.5, 19.3}},
HM{AE{2.1, 4.2}, std::nullopt},
};
auto minmax = std::minmax_element(vec.begin(), vec.end(), CompareHM);
auto min = std::min_element(vec.begin(), vec.end(), CompareHMMin);
auto max = std::max_element(vec.begin(), vec.end(), CompareHMMax);
// Print the results
std::cout << "Correct Min A value: " << min->H->A << "\n";
std::cout << "Correct Max A value: " << max->H->A << "\n";
std::cout << "Incorrect Min A value using minmax_element: " << minmax.first->H->A << "\n";
std::cout << "Incorrect Max A value using minmax_element: " << minmax.second->H->A << "\n";
return 0;
}
输出:
Correct Min A value: 0.9
Correct Max A value: 2.3
Incorrect Min A value using minmax_element: 1.8
Incorrect Max A value using minmax_element: 2.1
2条答案
按热度按时间kpbwa7wx1#
CompareHM
不会导致 * 严格弱序 *,这就是为什么std::minmax_element
会给出无意义的结果。严格弱序需要是传递的,而不可比较的元素打破了这一点:
这意味着对于 * 严格弱序 * 必须为真,但当
std::nullopt
是不可比较的时显然不是。不可比性需要是一种传递关系,即
但如果
a
与b
相当,情况显然不是这样。顺便说一下,这也是为什么你不能对包含NaN的float
s的范围进行排序的原因(参见Is NaN a valid key value for associative containers?)。与
Min
和Max
关系不同,我们不能简单地将std::nullopt
视为正/负无穷大值。C++17或更早版本
在旧的C++标准中,可以使用remove-erase习惯用法中的
std::remove_if
就地消除std::nullopt
元素:实际上,如果您的目标只是找到最小和最大元素,那么只使用
std::remove_if
就足够了。显然,总是可以选择分别使用std::min_element
和std::max_element
。C++20
我们可以使用
std::ranges::filter_view
来查看没有任何std::nullopt
元素的范围,允许std::ranges::minmax_element
正确工作。zzzyeukh2#
一个大问题是,为了使用
std::minmax_element
,你需要决定一个无值的optional
应该大于还是小于一个有值的可选值。不可能两者都是一个简单的解决方案是排除H
是无值的HM
s,首先通过划分vector
。您也可以使用
default
operator<=>
来简化此操作。对于optional
:T
)。否则这对于需要 * 严格的周排序 * 的算法很好,所以:
然后将
vector
分区,以将HM
与无值H
放在vector
的最后:然后
minmax_element
可以完成它的任务:Demo
如果你不想对
vector
进行分区,你也可以使用ranges::filter_view
,比如Jan showed,只是你不需要自定义比较器。在C++17和更早版本中,您可以为两个类定义
operator<
,以便简化工作。仍然不需要复杂的定制比较器:分区和调用
minmax_element
的工作原理与上面的相同。