将一元函数应用于向量的某些元素的良好实现是什么?

What's a good implementation of applying a unary function to some elements of a vector?

本文关键字:元素 是什么 实现 向量 一元 应用于 函数      更新时间:2023-10-16

我想将函数UnaryFunction f应用于 std 容器的某些元素,给定谓词UnaryPredicate p - 如果您组合std::partition然后将std::for_each应用于其中一个分区,您会得到什么。

我对C++很陌生,所以请原谅我的无知。但是,我已经在<algorithm>中寻找合适的实现,但我似乎找不到所需的功能。

基于 cppreference.com 可能的实现,我想出了以下内容:

template<class InputIt, class UnaryPredicate, class UnaryFunction>
UnaryFunction for_each_if(InputIt first, InputIt last, UnaryPredicate p, UnaryFunction f)
{
    for (; first != last; ++first) {
        if (p(*first))
        {
            f(*first);    
        }        
    }
    return f;
}

返回值是按照std::for_each建模的,尽管OutputIter可能是更好的选择。不过,这需要一个更复杂的实现,所以这次我选择了简洁而不是技巧。替代实现留给读者作为练习。

我的问题是:在 std 库中是否已经有既定的方法可以做到这一点?如果不是,这是否是此类函数模板的合理实现?

STL不能很好地支持算法的组合。正如你所说,你可以先调用partition,然后如果你不关心元素的顺序,可以在其中一个分区上调用for_each

对于一个新项目,或者一个可以引入库的项目,我强烈建议你看看一个范围库,例如 Boost.Range 或 Eric Niebler 的 range-v3。

使用范围库,可以像这样完成:

template<typename R, typename P, typename F> 
F for_each_if(R& rng, P pred, F f)
{ 
    using namespace boost::adaptors;
    return (rng | filtered(pred) | for_each(f));
}

就评论而言,在 std 库中似乎没有实现这一点。但是,正如user2672165所指出的,谓词可以很容易地包含在函数中。为了说明这一点,请参阅 cppreference.com 的以下修改版本的for_each示例:

#include <vector>
#include <algorithm>
#include <iostream>
struct Sum {
    Sum() { sum = 0; }
    void operator()(int n) { sum += n; }
    int sum;
};
int main()
{
    std::vector<int> nums{3, 4, 2, 9, 15, 267};
    std::cout << "before: ";
    for (auto n : nums) {
        std::cout << n << " ";
    }
    std::cout << 'n';
    std::for_each(nums.begin(), nums.end(), [](int &n){ if (n > 5) n++; });
    // Calls Sum::operator() for each number
    Sum s = std::for_each(nums.begin(), nums.end(), Sum());
    std::cout << "after:  ";
    for (auto n : nums) {
        std::cout << n << " ";
    }
    std::cout << 'n';
    std::cout << "sum: " << s.sum << 'n';
}

在这里,谓词被添加到函数中,因此[](int &n){ n++; }现在变得[](int &n){ if (n > 5) n++; }仅将函数应用于大于 5 的整数元素。

预期输出为

before: 3 4 2 9 15 267 
after:  3 4 2 10 16 268 
sum: 303

希望这对其他人有所帮助。