STL上的C ++ lambda函数机制累积

时间:2013-12-30 10:45:19

标签: c++ lambda

我正在学习新的C ++ 11 lambda特性,这段代码究竟是如何使用lambdas计算数组(双精度)的乘积?

double product2 = accumulate(begin(doubles), end(doubles), 1.0,
    [](double partialresult, double d){return partialresult*d; });

我想了解变量partialresult和d来自/去的位置。

3 个答案:

答案 0 :(得分:1)

std :: accumulate for double的特化,将在概念上类似于以下实现(为简单起见,删除了模板参数语法):

double accumulate(
    iterator_type begin, iterator_type end,
    double initial, functor_type f)
{
    double partialResult = initial;
    while(begin != end)
        partialResult = f(partialResult, *begin++);
    return partialResult;
}

基本上,部分结果是每一步积累的中间结果。 d将是迭代器指向的值。

答案 1 :(得分:0)

执行此操作的旧方法是创建一个重载operator()(称为函子或函数对象)m的类,或者使用自由函数来执行此操作:

class product
{
public:

    double operator()(double a, double b) const
    {
        return a * b;
    }
};

或简单地说:

double product(double a, double b) { return a * b; }

在引擎盖下,编译器将lambdas翻译成类似上面的形式:

class <implementation_defined_unique_name>
{
    // Implementation of operator() effectively as before
};

要了解accumulate的工作原理,查看可能的实现可能有所帮助(来自en.cppreference.com):

template<class InputIt, class T, class BinaryOperation>
T accumulate(InputIt first, InputIt last, T init, 
             BinaryOperation op)
{
    for (; first != last; ++first) {
        init = op(init, *first);
    }
    return init;
}

这里,它只是调用提供的函数,从序列中的初始值和第一个值开始。然后它存储它,并调用函数,第一个调用的结果作为第一个参数,序列中的下一个值作为第二个参数,依此类推。

答案 2 :(得分:0)

要了解算法是如何工作的,我建议自己编写一个计算产品的代码。它可以看作以下方式

double doubles[] = { /* some initializers for the array */ };

double init = 1.0;

double acc = init;
for ( auto it = begin( doubles ); it != end( doubles ); ++it )
{
   acc = acc * *it;
} 

您可以将代码重写为函数

double accumulate( double *first, double *last, double init_value )
{
   double acc = init;

   for ( ; first != last; ++first )
   {
      acc = acc * *first;
   }

   return ( acc );
}  

函数调用将显示

accumulate( begin( doubles ), end( doubles ), 1.0 );

然而标准算法std :: accumulate使用operator +而不是operator *。因此,如果您需要替换operator + for operator *,您可以按以下方式重写该函数

double accumulate( double *first, double *last, double init_value, std::multiplies<double> Op )
{
   double acc = init;

   for ( ; first != last; ++first )
   {
      acc = Op( acc, *first );
   }

   return ( acc );
}  

如果将函数定义为模板函数,则可以使用任何二进制操作代替std :: multiplies。所以我将进一步参考标准算法。您可以使用标准二进制操作std :: multiplies

编写上面的原始代码
double product2 = accumulate( begin( doubles ), end( doubles ), 1.0,
    multipliers<double>() );

由于函数是模板函数,因此可以将std :: multipliers替换为lambda表达式

double product2 = accumulate(begin(doubles), end(doubles), 1.0,
    [](double partialresult, double d){return partialresult*d; });

如果我们为lambda表达式指定一个名称

,可以写得更清楚
auto multipliers = [](double partialresult, double d){return partialresult*d; };

当算法的调用看起来

double product2 = accumulate(begin(doubles), end(doubles), 1.0,
    multipliers() );

在其体内而不是标准函数对象std :: multipliers中,将调用lambda表达式的运算符函数。