Как передать лямбда-функцию в функторе с ++? - PullRequest
2 голосов
/ 16 апреля 2019

Я довольно новичок в Rccp и Rccpparallel, и мне трудно понять, где я допустил ошибку. Поэтому я хочу создать функцию, которая будет выполнять параллельное включение элемента мощности в матрицу. Я следую rcppParallel примеры.

На одном ядре код компилируется и работает нормально, но когда я пытаюсь передать n функтору ниже, я получаю следующую ошибку.

capture of non-variable "Power::n"
"this" was not captured for this lambda function
invalid use of non-static data member "Power::n"

Если я поменяю n в функторе ниже, он компилируется и работает нормально. Что мне не хватает? R код:

library(Rcpp)
library(RcppParallel)
Sys.setenv("PKG_CXXFLAGS"="-std=c++11")
sourceCpp("lambdaPower.cpp")

lambdaPower.cpp

#include <Rcpp.h>
using namespace Rcpp;

#include <cmath>
#include <algorithm>

// [[Rcpp::export]]
NumericMatrix matrixPower(NumericMatrix orig, double n)
{

    // allocate the matrix we will return
    NumericMatrix mat(orig.nrow(), orig.ncol());

    // transform it
    std::transform(orig.begin(), orig.end(), mat.begin(), [n](double x) { return pow(x, n); });

    // return the new matrix
    return mat;
}

// [[Rcpp::depends(RcppParallel)]]
#include <RcppParallel.h>
using namespace RcppParallel;

struct Power : public Worker
{
    // source matrix
    const RMatrix<double> input;

    // destination matrix
    RMatrix<double> output;

    //power
    double n;


    // initialize with source and destination
    Power(const NumericMatrix input, NumericMatrix output, double n)
        : input(input), output(output), n(n){}
    // take the n power of the range of elements requested
    void operator()(std::size_t begin, std::size_t end)
    {
        std::transform(input.begin() + begin,
                       input.begin() + end,
                       output.begin() + begin,
                       [n](double x) { return pow(x,n); }); // why n doesn work?
                    // If i swap n with fixed number it compiles and works.
                    // [](double x) { return pow(x,2); }); compiles and works
    }
};

// [[Rcpp::export]]
NumericMatrix parallelMatrixPower(NumericMatrix x, double n)
{

    // allocate the output matrix
    NumericMatrix output(x.nrow(), x.ncol());

    // power functor (pass input and output matrixes)
    Power power(x, output, n);

    // call parallelFor to do the work
    parallelFor(0, x.length(), power);

    // return the output matrix
    return output;
}

Большое спасибо.

1 Ответ

4 голосов
/ 16 апреля 2019

Вы компилируете код, если скопируете n в область, где определяется лямбда:

....
  void operator()(std::size_t begin, std::size_t end)
  {
    auto _n = n;
    std::transform(input.begin() + begin,
                   input.begin() + end,
                   output.begin() + begin,
                   [_n](double x) { return pow(x,_n); });
  }
....

Я не очень хорош в объяснении этого, но вы можете прочитать подробности в "Item 31: Избегайте режимов захвата по умолчанию" в "Effective Modern C ++" Скотта Мейерса.

Кстати, вместо Sys.setenv("PKG_CXXFLAGS"="-std=c++11") в коде R я бы использовал // [[Rcpp::plugins(cpp11)]] в коде C ++.

...