简体   繁体   中英

How can I pass a function as an optional parameter in C++?

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!

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

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 , eg

[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;    
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM