Home > front end >  How can I pass a function as an optional parameter in C ?
How can I pass a function as an optional parameter in C ?

Time:08-24

I have two functions that are quite similar, so I'm trying reduce the code duplication. I thought I can create a new function MyFunction() that be called both with or without a func that can be optionally applied to the arguments. So the default for func should be a function that just returns i. I'm not sure if my code is correct and also couldn't find out how to define a default function. I have something like this (comment out MyFunction to run the code)


#include <vector>
#include <string>
#include <algorithm>
#include <cctype>
#include <iomanip>
#include <iostream>

int somefunc(int b, int i){
    return i-b; // simplified
}

std::vector<int> MyOldFunction1(const int a,
                            std::vector<int> list) {
          std::transform(list.begin(), list.end(), list.begin(), 
                      [a](int i) -> int {return a*i;});
       return list;
}

std::vector<int> MyOldFunction2(const int a,
                            std::vector<int> list,
                            const int b) {
          std::transform(list.begin(), list.end(), list.begin(), 
                      [a,b](int i) -> int {return a*somefunc(b,i);});
       return list;
}

// Suggested combination (not working)
std::vector<int> MyFunction(const int a,
                            std::vector<int> list, std::function<int,int> &f,
                            const int b) {
          std::transform(list.begin(), list.end(), list.begin(), 
                      [a,b](int i) -> int {return a*f(b,i);});
       return list;
}

void PrintVector(std::vector<int> a) {
    for(auto i=a.begin(); i!=a.end();   i){
        std::cout<<(*i);
    }
    std::cout<<std::endl;
}


int main () {
    int p[] = {1, 2, 3, 4, 5};
    std::vector<int> a(p, p 5);
    PrintVector(MyOldFunction1(1,a)); // 1,2,3,4,5
    PrintVector(MyOldFunction2(1,a,1)); // 0,1,2,3,4

}

Is there a more efficient/clean way to do this? Any advice is appreciated!

CodePudding user response:

You can have a default parameter of type std::function<int(int)>, e.g.

std::vector<int> MyFunction(const int a, 
                            std::vector<int> list, 
                            std::function<int(int)> func = [](int i) -> int { return i; }) {
    std::transform(list.begin(), list.end(), list.begin(), [a, func](int i) -> int { return a*func(i); });
   return list;    
}

You can then pass a lambda that calls somefunc with your b, e.g.

[b = 2](int i) -> int { return somefunc(b, i); }

See it on coliru

Aside: You need to drop the const from the parameter list if you intend to modify it in the body.

Further aside: With C 20 you can template this and still communicate that func must accept an int and return an int:

template<typename Func = decltype([](int i) -> int { return i; })>
requires(std::is_invocable_r_v<int, Func, int>)
std::vector<int> MyFunction(const int a, 
                            std::vector<int> list, 
                            Func func = {}) {
    std::transform(list.begin(), list.end(), list.begin(), [a, func](int i) -> int { return a*func(i); });
   return list;    
}
  •  Tags:  
  • c
  • Related