2
votes

I have a problem while using Rcpp on Mac (on Windows the problem does not occur).

Here is the C++ Code that causes the error.

#include <Rcpp.h>
using namespace Rcpp;

NumericVector vecpow(const IntegerVector base, const NumericVector exp) 
{
  NumericVector out(base.size());
  std::transform(base.begin(), base.end(), exp.begin(), out.begin(), ::pow);
  return out;
}

Seems like nothing too fancy or complicated.

Still I get the following error when I try to compile it:

na_ma.cpp:7:3: error: no matching function for call to 'transform' std::transform(base.begin(), base.end(), exp.begin(), out.begin(), ::pow); ^~~~~~~~~~~~~~

/Library/Developer/CommandLineTools/usr/include/c++/v1/algorithm:2028:1: note: candidate function template not viable: requires 4 arguments, but 5 were provided transform(_InputIterator __first, _InputIterator __last, _OutputIterator __result, _UnaryOperation __op) ^

I am wondering how to fix this. While searching for solutions I came to some suggestions to create a Makevars file - but this did not work for me.

Would be also nice, if somebody could explain to me, why this error is occurring since I don't understand it.

1
Works for me with g++ and clang++ on Linux (once I add the missing lines; would be nice if you submit a complete example next time). I suggest you check your macOS header files / added header files. - Dirk Eddelbuettel
@DirkEddelbuettel this is more of a (older) compiler issue, just pack ::pow into lambda - Severin Pappadeux
Well, maybe not as OP states success on Windows where R imposes g++ version 4.9.3. - Dirk Eddelbuettel
@DirkEddelbuettel well, on Mac usually it is older Apple-patched clang, so one might expect differences. - Severin Pappadeux
I don't know. Works for me with clang++-4.0 (the oldest one I have around) as well as the newer default. - Dirk Eddelbuettel

1 Answers

5
votes

This is actually C++ compiler error. Compiler cannot match ::pow with BinaryOp, so pack it into lambda. This works for me

std::transform(base.cbegin(), base.cend(), exp.cbegin(), out.begin(), [](double a, double b) {return ::pow(a, b); });

If lambdas are not available, one could try to make a functor (which lambda is equivalent to, please check https://medium.com/@winwardo/c-lambdas-arent-magic-part-1-b56df2d92ad2, https://medium.com/@winwardo/c-lambdas-arent-magic-part-2-ce0b48934809). Along the lines (untested code, I'm not at my computer)

struct pow_wrapper {
    public: double operator()(double a, double b) {
        return ::pow(a, b);
    }
};

Then try

std::transform(base.cbegin(), base.cend(), exp.cbegin(), out.begin(), pow_wrapper());