Home > Enterprise >  Convert a function pointer to another having more arguments
Convert a function pointer to another having more arguments

Time:11-13

Suppose I am trying to use a function which accepts a binary function and calls it with some arguments:

typedef double (*BinaryFunction)(double a, double b);
typedef double (*UnaryFunction)(double a);

// Can't change this
double ExternalFunction(BinaryFunction binaryFunction)
{
    return binaryFunction(1, 2);
}

Now suppose a user of my code is going to provide me with a unary function. My goal is to convert it into a binary function so that I can call ExternalFunction with it:

double MyFunction(UnaryFunction unaryFunction)
{
    BinaryFunction binaryFunction = /* want a function (a, b) -> unaryFunction(a   b) */;
    return ExternalFunction(binaryFunction);
}

How do I do this? Just to be clear, I understand that this would be easy if the unary function were known at compile time, but it's not - it will be an argument to my function. Thanks in advance.


Here's a summary of my attempts. I believe I understand why these don't work, but I'm providing them so you can see what I've been thinking so far.

I can't use a lambda, because I'd have to capture UnaryFunction, and capturing lambdas can't be converted to function pointers:

double MyFunction(UnaryFunction unaryFunction)
{
    BinaryFunction binaryFunction = [unaryFunction](double a, double b){ return unaryFunction(a   b); };
    return ExternalFunction(binaryFunction);
}

Use std::function ? Can't get that to work either:

void MyFunction(UnaryFunction unaryFunction)
{
    std::function<double(double, double)> binaryFunctionTemp = [unaryFunction](double a, double b)
    {
        return unaryFunction(a   b);
    };
    BinaryFunction binaryFunction = binaryFunctionTemp.target<double(double, double)>();
    ExternalFunction(binaryFunction);
}

What about a function object? Won't work because we'd need a pointer to a member function:

class BinaryFromUnary
{
public:
    BinaryFromUnary(UnaryFunction unaryFunction) : unary_(unaryFunction) {};
    double operator()(double a, double b)
    {
        return unary_(a   b);
    }
private:
    UnaryFunction unary_;
};

void MyFunction(UnaryFunction unaryFunction)
{
    BinaryFromUnary functionObject(unaryFunction);
    std::function<double(double, double)> binaryFunction = functionObject;
    ExternalFunction(binaryFunction.target<double(double, double)>());
}

Even had a go with std::bind (and probably messed it up):

struct Converter {
    Converter(UnaryFunction unary) : unary_(unary) {}
    double binary(double a, double b) const { return unary_(a   b); }
    UnaryFunction unary_;
};

void MyFunction(UnaryFunction unaryFunction)
{
    Converter converter(unaryFunction);
    std::function<double(double, double)> binaryFunction = std::bind( &Converter::binary, converter, _1, _2);
    ExternalFunction(binaryFunction.target<double(double, double)>());
}

Tried a couple of other things along the same lines. Any ideas would be much appreciated.

CodePudding user response:

Use an external variable to hold the unary function.

Include standard disclaimers about how inelegant and non-thread safe this is, etc. but at least this is a hack consistent with the stated requirements:

#include <iostream>

typedef double (*BinaryFunction)(double a, double b);
typedef double (*UnaryFunction)(double a);

// Can't change this
double ExternalFunction(BinaryFunction binaryFunction) {
  return binaryFunction(1, 2);
}

namespace foo {
UnaryFunction unaryFunction;
}

double MyBinaryFunction(double a, double b) {
  return foo::unaryFunction(a   b);
}

double MyUnaryFunction(double a) {
  return 2 * a;
}

double MyFunction(UnaryFunction unaryFunction) {
  foo::unaryFunction = unaryFunction;
  BinaryFunction binaryFunction = MyBinaryFunction;
  return ExternalFunction(binaryFunction);
}

int main() {
  std::cout << MyFunction(MyUnaryFunction) << std::endl;  // 6
  return 0;
}

CodePudding user response:

I don't know your exact use-case, but there's a chance this might help you:

typedef double (*BinaryFunction)(double a, double b);
typedef double (*UnaryFunction)(double a);

// Can't change this
double ExternalFunction(BinaryFunction binaryFunction)
{
    return binaryFunction(1, 2);
}

// If you always know the unary function at compile time:

// Create a wrapper function with the BinaryFunction signature that takes
// a unary function as a NTTP:
template <UnaryFunction unaryFunction>
double wrapper(double a, double b)
{
    return unaryFunction(a   b);
}

// Simply use this wrapper to implement MyFunction as follows:
template <UnaryFunction unaryFunction>
double MyFunction()
{
    return ExternalFunction(wrapper<unaryFunction>);
}

// Using it:

double unary1(double x) { return x * 2; }
double unary2(double x) { return x * 3; }

int main()
{
    std::cout << MyFunction<unary1>() << '\n';
    std::cout << MyFunction<unary2>() << '\n'; 
}

Have a godbolt link to play around with it as well.

Unlike the other answer, this doesn't require a global, but this also only works if you always know your function at compile-time, which there's a good chance you don't, so sorry in advance. Hope it was still interesting.

  •  Tags:  
  • c
  • Related