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