在一元函数上使用 STL 算法
Using STL algorithms on unary functions
所以我经常想对一系列元素执行一些 STL 算法,而不是比较函数,我想传递一个一元函数 f。
比如我想写这样的东西
std::max_element(begin(range), end(range), f);
在应用 f 后找到范围内的最大元素。
我目前的解决方法看起来像这样:
std::max_element(begin(range), end(range, [&f](auto a, auto b){ return f(a) < f(b); });
乍一看,这似乎没有问题。但是 f 本身可以是一个 lambda 表达式,或者比 f 更复杂的其他方式。
那段代码有两个问题:
a) 它很容易出错,因为可能会不小心写成 f(a) < f(a)(特别是如果更复杂并且使用了副本和过去)。这是代码重复的问题
b) 它没有很好地表达意图。如果我想按函数排序,我不想处理比较。
很遗憾我在标准库(甚至boost)中都没有找到很好的解决这类问题的方法,所以想请教一下你对这个问题的解决方法是什么。算法中不存在此重载是否有任何原因?
使用 c++ 20 的范围你可以做到:
std::ranges::max_element(range | std::views::transform(f));
您可以做的一件事是创建您自己的通用比较器,它接受一元函数来执行转换:
// Generic comparator
template<typename T, typename F>
struct transform_comparator_type
{
transform_comparator_type(F f): f(f) {}
bool operator()(T const& a, T const& b) const { return f(a) < f(b); }
F f;
};
// Helper function to deduce the type of F
template<typename T, typename F>
auto transform_comparator(F f)
{
return transform_comparator_type<T, F>(f);
}
int main()
{
std::vector<int> v{1, 4, 3, 6, 0};
auto e = std::max_element(std::begin(v), std::end(v),
transform_comparator<int>([v](int i){ return 2 * i; }));
// etc...
}
编辑添加:
类型实际上可以从提供的转换函数的 return 类型推导出来,因此您不需要辅助函数。您可以这样做:
template<typename F>
struct transform_comparator
{
using T = decltype(F()({})); // deduce T from return type of F
transform_comparator(F f): f(f) {}
bool operator()(T const& a, T const& b) const { return f(a) < f(b); }
F f;
};
所以我经常想对一系列元素执行一些 STL 算法,而不是比较函数,我想传递一个一元函数 f。
比如我想写这样的东西
std::max_element(begin(range), end(range), f);
在应用 f 后找到范围内的最大元素。 我目前的解决方法看起来像这样:
std::max_element(begin(range), end(range, [&f](auto a, auto b){ return f(a) < f(b); });
乍一看,这似乎没有问题。但是 f 本身可以是一个 lambda 表达式,或者比 f 更复杂的其他方式。 那段代码有两个问题: a) 它很容易出错,因为可能会不小心写成 f(a) < f(a)(特别是如果更复杂并且使用了副本和过去)。这是代码重复的问题 b) 它没有很好地表达意图。如果我想按函数排序,我不想处理比较。
很遗憾我在标准库(甚至boost)中都没有找到很好的解决这类问题的方法,所以想请教一下你对这个问题的解决方法是什么。算法中不存在此重载是否有任何原因?
使用 c++ 20 的范围你可以做到:
std::ranges::max_element(range | std::views::transform(f));
您可以做的一件事是创建您自己的通用比较器,它接受一元函数来执行转换:
// Generic comparator
template<typename T, typename F>
struct transform_comparator_type
{
transform_comparator_type(F f): f(f) {}
bool operator()(T const& a, T const& b) const { return f(a) < f(b); }
F f;
};
// Helper function to deduce the type of F
template<typename T, typename F>
auto transform_comparator(F f)
{
return transform_comparator_type<T, F>(f);
}
int main()
{
std::vector<int> v{1, 4, 3, 6, 0};
auto e = std::max_element(std::begin(v), std::end(v),
transform_comparator<int>([v](int i){ return 2 * i; }));
// etc...
}
编辑添加:
类型实际上可以从提供的转换函数的 return 类型推导出来,因此您不需要辅助函数。您可以这样做:
template<typename F>
struct transform_comparator
{
using T = decltype(F()({})); // deduce T from return type of F
transform_comparator(F f): f(f) {}
bool operator()(T const& a, T const& b) const { return f(a) < f(b); }
F f;
};