Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

defining a function inside a function in c

Tags:

c++

c

I want to create a general function which returns a function pointer to another function in C/C++. However, second returned function should be able to use variable from first function.

Example,

typedef double (*func_t)(double);

func_t inverse(func_t fn) {
   // define another function here that uses fn
   double solve(double x) {
      // use fn
   }
   return &solve;
}

double sqr(double x) { return x * x; }

int main() {
     func_t inv = inverse(sqr);
     printf("sqrt %d = %f\n", 100, inv(100)); 
}

Obviously gcc, g++ do not allow me to do this. Can I achieve this without using classes or structs.

like image 315
morazow Avatar asked Oct 22 '13 19:10

morazow


4 Answers

This is not about nested functions; this is about closures. GCC's nested functions are a half-implemented form of closure that does not do what the question is asking for.

C, going by any of the standards, does not support closures at all.

C++11 supports closures through lambdas, and there are a few other solutions specific to C++ as well.

Apple's Clang compiler does support closures as an extension in C mode, in the form of "blocks". Unlike nested functions, these actually work for the requested use case (i.e. being returned to a higher call level).

You'd write it out something like this:

typedef double (^func_t)(double);  // block type is slightly different from function pointer

func_t inverse(func_t fn) {
   return ^ double(double x) {
       //use fn
   };
}

// ...etc., same from here

But if you want to make extensive use of closures, you really need to use a different language. You'll run into serious complications in C because of the lack of any kind of memory management (unrestricted closures are a nightmare to manage by hand).

like image 57
Leushenko Avatar answered Sep 18 '22 10:09

Leushenko


Answering for C:

C does not support nested functions (defining a function inside another function) but gcc allows it as a GNU extension to C.

http://gcc.gnu.org/onlinedocs/gcc/Nested-Functions.html

like image 20
ouah Avatar answered Sep 20 '22 10:09

ouah


This is possible in C++11 with a lambda:

#include <cstdio>
#include <cmath>
#include <functional>

typedef std::function<double(double)> func_t;

func_t inverse(func_t fn) {
    return [=](double x) { printf("fn(x): %f\n", fn(x)); return sqrt(x); };
}

double sqr(double x) { return x * x; }

int main() {
    auto inv = inverse(sqr);
    printf("sqrt %d = %f\n", 100, inv(100));
}
like image 27
mattnewport Avatar answered Sep 17 '22 10:09

mattnewport


If you can use C++11, them lambda functions are your friend:

#include <functional>
#include <iostream>

std::function<double(double)> identity(std::function<double(double)> fn)
{
  return [fn](double x){
    // Do your logic here
    return fn(x);
  };
}

double sqr(double x) { return x * x; }

int main() {
  auto f = identity(sqr);
  std::cout << "sqr(100) = " << f(100) << std::endl;
}

If you don't plan to support C++11, you can do this way:

#include <iostream>

typedef double (*func_t)(double);
struct func
{
  func_t fn;
  double (*calc)(func_t, double);
  double operator()(double x) {return calc(fn, x);}
};

double identity_calc(func_t fn, double x) {return fn(x);}

func identity(func_t fn)
{
  func f = {fn, identity_calc};
  return f;
}

double sqr(double x) { return x * x; }

int main() {
  func f = identity(sqr);
  std::cout << "sqr(100) = " << f(100) << std::endl;
}

But I don't think you will have much luck with plain C.

like image 37
Guilherme Bernal Avatar answered Sep 17 '22 10:09

Guilherme Bernal