STL 算法之for_each

for_each

for_each算法定义在<algorithm>头文件中,需要在使用该算法时include<algorithm>头文件。

std::for_each的功能是对区间[first,last)上的每一个元素调用function,第三个参数可以全局函数,函数对象,lambda表达式,并且是一个一元函数。

其定义如下,各编译器实现可能不同:

template< class InputIt, class UnaryFunction >
UnaryFunction for_each( InputIt first, InputIt last, UnaryFunction function );
  • 功能:对区间[first, last)中的每一个元素调用function 。

  • 参数first,last:指定该算法操作的区间[first, last)。

  • 参数function : 一元函数,即UnaryFunction ,可以是全局函数(函数指针),函数对象,lambda等,默认按值传递。

  • 返回值:返回function 的一个副本,function的任何返回值都将被忽略.

  • 复杂度:log(n), 与区间中的元素个数呈线性变换。

注意:第三个参数function默认是按值传递的。也就是说,std::for_each内部操作的是function的副本,另外,返回值也是按值返回的。当然,你也可以打破这种限制(参考:Effective STL 的38条款)

尽管我们可以使用完全for来实现相同的目的,但是std::for_each可以节省时间和代码数量,也减少了一些错误的机会。

示例1:打印纯数组(C数组)中的元素。

//static全局函数
static void printElement(int &item)
{
    std::cout << item << " ";
}

//函数对象类
class Printer
{
public:
    void operator()(int& item){std::cout << item<<" ";}
    
};

int main(int argc, char *argv[])
{
    int plainArray[] {2,6,3,1,9,8,10,5,4,0};
    
    //第三个参数为static全局函数
    std::for_each(std::begin(plainArray), std::end(plainArray), printElement);
    std::cout << std::endl;
    
    //第三个参数为lambda
    std::for_each(std::begin(plainArray), std::end(plainArray), [](int &Item){std::cout << Item << " ";});
    std::cout << std::endl;
    
    //第三个参数为函数对象
    std::for_each(std::begin(plainArray), std::end(plainArray), Printer());
    std::cout << std::endl;
    
    return 0;
}

示例2:std::for_each的返回值。

有时候,我们可以充分利用std::for_each的返回值完成一些事情。比如,计算容器/数组元素的sum。

我们可以使用std::for_each和函数对象来完成这个功能。

class Sum{
    
public:
    Sum():sum{0}
    {
        
    }
    
    void operator()(const int& item)
    {
        sum +=item;
    }
    
    int getSum(){
        return sum;
    }
private:
    int sum;
};

int main(int argc, char *argv[])
{
    std::vector<int> nums{0,1,2,3,4,5,6,7,8,9};
    
    Sum elements = std::for_each(nums.begin(), nums.end(),Sum());
    
    std::cout << elements.getSum() << std::endl;
    return 0;
}

示例3:验证第三个参数默认是按值传递的。

class Sum{
    
public:
    Sum():sum{0}
    {
        
    }
    
    void operator()(const int& item)
    {
        sum +=item;
    }
    
    int getSum(){
        return sum;
    }
private:
    int sum;
};

int main(int argc, char *argv[])
{
    std::vector<int> nums{0,1,2,3,4,5,6,7,8,9};
    
    Sum Temp;
    std::cout << "Begin, Temp'sum = "<< Temp.getSum() << std::endl;
    std::for_each(nums.begin(), nums.end(),Temp);
    std::cout << "After, Temp'sum = "<< Temp.getSum() << std::endl;
    
    
    return 0;
}

输出:

Begin, Temp’ sum = 0
After, Temp’ sum = 0

那么,如果我们真的需要第三个参数按引用传递,我们可以这个做:

int main(int argc, char *argv[])
{
    std::vector<int> nums{0,1,2,3,4,5,6,7,8,9};
    
    Sum Temp;
    std::cout << "Begin, Temp'sum = "<< Temp.getSum() << std::endl;
    
    //显示指定std::for_each的第二个模板参数按引用传递,此时返回值和第三个参数都是按引用传递。
    std::for_each<std::vector<int>::iterator, Sum&>(nums.begin(), nums.end(),Temp);
    std::cout << "After, Temp'sum = "<< Temp.getSum() << std::endl;
    
    return 0;
}

输出:

Begin, Temp’sum = 0
After, Temp’sum = 45

虽然按引用传递可能会达成某种目的,但是不推荐这么做。

参考

  • https://thispointer.com/stdfor_each-tutorial-usage-details-with-examples/
  • https://docs.microsoft.com/zh-cn/cpp/standard-library/algorithm-functions?view=vs-2019#for_each
  • https://en.cppreference.com/w/cpp/algorithm/for_each_n

你可能感兴趣的:(C++,STL)