【问题标题】:Using STL algorithms on unary functions在一元函数上使用 STL 算法
【发布时间】:2020-12-24 10:05:29
【问题描述】:

所以我经常想对一系列元素执行一些 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)

很遗憾,我在标准库(甚至是boost)中没有找到解决这类问题的好方法,所以想问一下你对这个问题的解决方案是什么。算法中不存在这种重载有什么原因吗?

【问题讨论】:

  • Boost 的transform iterator 似乎正是您要找的。换句话说,应该调整的是您传递给 max_element 的迭代器,而不是比较器。
  • 对于标准库,使用现有函数是不可能的。您需要std::transformmax_element 的组合。您可以编写一个非常简单的模板化包装函数来实现这一点。这并不复杂。 3 行代码。 . .
  • 感谢这个想法!我仍然不知道如何避免这个问题。那里给出的例子也存在代码重复的问题。
  • 标准库函数不能涵盖所有可能的需求。总会有一些时候你需要一些不同的东西。您始终可以编写自己的函数来满足您的特定需求。您仍然可以利用标准库来完成这项任务的核心部分。
  • 这能回答你的问题吗? Very generic argmax function in C++ wanted

标签: c++ c++-standard-library


【解决方案1】:

使用 c++ 20 的范围你可以做到:

std::ranges::max_element(range | std::views::transform(f));

【讨论】:

  • 为什么不将投影(第三个参数)传递给 max_element?
  • 我认为最终是一样的,但是是的,这也可以max_element(range, {}, f);
  • 我个人更喜欢第一个版本,因为调用转换 self-documents 代码,而第二个版本如果您不熟悉则不清楚
  • 不幸的是,我目前只能访问 c++17,但这将很好地解决问题!我更喜欢第二个版本,因为可以假设熟悉标准库。
  • 你可以看看 eric niebler 的 range v3 库,它应该像这样工作并且是 c++17 (我认为),一旦你有了,你应该能够插入并用 stl 替换c++20访问
【解决方案2】:

您可以做的一件事是创建自己的通用比较器,该比较器接受一元函数来执行转换:

// 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...
}

编辑添加:

类型实际上可以从提供的转换函数的返回类型推导出来,因此您不需要辅助函数。你可以这样做:

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

【讨论】:

  • 这看起来是 c++17 的一个很好的解决方案,它也解决了一个更普遍的问题。我也在 STL 或 boost 中寻找过类似的东西,但没有找到,这在 IMO 很奇怪,因为这是一个常见问题(或者不是?)。
  • 我认为大多数人只会在需要的地方将比较器写成 lambda。
猜你喜欢
  • 1970-01-01
  • 2018-09-18
  • 1970-01-01
  • 2011-08-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多