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

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

我想将函数 UnaryFunction f 应用于 std 容器的某些元素,给定谓词 UnaryPredicate p - 如果将 std::partition and then apply 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;
}

return 值是根据 std::for_each 建模的,尽管 OutputIter 可能是更好的选择。不过这需要更复杂的实现,所以这次我选择了简洁而不是巧妙。替代实现留作 reader.

的练习

我的问题是:在 std 库中是否已经建立了执行此操作的方法?如果不是,这是否是这样一个函数模板的合理实现?

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

#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

希望这对其他人有帮助。

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

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

有了range库,可以这样做:

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