简体   繁体   English

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

[英]C++ lambda function mechanism on STL accumulate

I am learning new C++ 11 lambda features, how exactly is this code calculating the product of an array (doubles) using lambdas? 我正在学习C ++ 11的lambda新功能,此代码如何精确地使用lambdas计算数组(双精度)的乘积?

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

I want to understand where the variables partialresult and d are coming from/going. 我想了解变量partialresult和d的来源/去向。

the specialization of std::accumulate for doubles, will have an implementation conceptually similar to the following (template arguments syntax removed for simplicity): std :: accumulate for doubles的专业化将在概念上类似于以下实现(为简单起见删除了模板参数语法):

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

Basically, the partial result is the intermediate result of the accumulation at each step. 基本上,部分结果是每个步骤累积的中间结果。 d will be the value pointed to by the iterator. d将是迭代器指向的值。

The old way of doing this was to make a class that overloaded operator() (known as functors or function objects)m, or use a free function to do it: 这样做的旧方法是创建一个使operator() (称为函子或函数对象)重载的类,或者使用自由函数来实现:

class product
{
public:

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

or simply: 或者简单地:

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

Under the hood, lambdas are translated by the compiler to something like the form above: 在幕后,lambda由编译器转换为上面的形式:

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

For understanding how accumulate works, looking at a possible implementation might help (from en.cppreference.com): 为了了解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;
}

Here, it simply calls the supplied function, starting with the initial value and the first value in the sequence. 在这里,它仅从序列中的初始值和第一个值开始调用提供的函数。 It then stores this, and calls the function with the result of the first call as the first parameter, and the next value in the sequence as the second parameter, and so on. 然后将其存储,并以第一次调用的结果作为第一个参数,并将序列中的下一个值作为第二个参数,以此类推。

That to understand how the algorithm works I advice to write yourself a code that calculates the product. 为了理解算法的工作原理,我建议您自己编写一个计算乘积的代码。 It can look the following way 它可以看起来如下

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

You can rewrite the code as a function 您可以将代码重写为函数

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

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

   return ( acc );
}  

The function call will look 函数调用将看起来

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

However the standard algorithm std::accumulate uses operator + instead of operator *. 但是,标准算法std :: accumulate使用运算符+代替运算符*。 So if you need substitute operator + for operator * you could rewrite the function the following way 因此,如果您需要用运算符+代替运算符*,则可以按以下方式重写函数

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

Instead of std::multiplies you could use any binary operation if the function would be defined as a template function. 如果将函数定义为模板函数,则可以使用任何二进制运算来代替std :: multiplies。 So further I will refer to the standard algorithm. 因此,我将进一步参考标准算法。 You could write your original code as above that is using standard binary operation std::multiplies 您可以使用标准二进制操作std :: multiplies编写上述原始代码。

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

As the function is a template function you can substitute std::multipliers for your lambda expression 由于该函数是模板函数,因此可以将std :: multipliers替换为lambda表达式

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

It can be written more clear if we assign the lambda expression a name 如果我们为lambda表达式分配一个名称,可以更清楚地写出

auto multipliers = [](double partialresult, double d){return partialresult*d; };

Whenthe call of the algorithm will look 何时调用算法

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

And inside its body instead of standard functional object std::multipliers operator function of your lambda expression will be called. 在其主体内部,而不是标准函数对象std :: multipliers运算符,您的lambda表达式将被调用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM