I want to create a function wrapper that calls two functions T1 func1() and T2 func2(T1) that I pass in and returns type T2. Here is what I got so far:
#include <functional>
#include <iostream>
template<typename T1, typename T2>
struct wrapper {
wrapper(T1(*f1)(), T2(*f2)(T1)) : func1(f1), func2(f2) {}
T2 operator() (void){
T1 val = func1();
// Here I want to do something with val
return func2(val);
}
std::function<T1(void)> func1;
std::function<T2(T1)> func2;
};
int f1() {return 42;}
double f2(int i) {return i/10.0;}
int main(){
wrapper<int, double> wrapped{f1, f2}; // I want to skip the <int, double> here
// wrapper wrapped{f1, f2}; // this only works for c++17 & later
// wrapper<f1, f2> wrapped; // is it possible to do this?
std::cout<<wrapped();
return 0;
}
It does work but has one issue: I need to provide template argument of <T1, T2> in the constructor which is a bit redundant (although I can skip them if using C++17).
I am wondering if it is possible to provide func1 and func2 as template argument, so I can write something like wrapper<func1, func2> wrapped?
EDIT:
after some experiment, I realized that I can declare the wrapper as:
template<typename T1, typename T2, T1(*f1)(), T2(*f2)(T1)>
then I can create the wrapper by:
wrapper<int, double, f1, f2> wrapped;
So f1 and f2 are in template argument, but I still need to provide the type.
MORE EDIT:
To clarify, the reason I think I need a class template rather than std::bind is that I need to store some variable inside the class for next call.
After more research, I found I can do this if using c++17:
#include <iostream>
#include <functional>
template<auto f1, auto f2>
struct wrapper {
using Tval = std::invoke_result_t<decltype(f1)>;
using Tret = std::invoke_result_t<decltype(f2), Tval>;
wrapper(Tret init) : m_last(init) {}
Tret operator() () {
auto val = f1();
auto res = m_last + f2(val);
m_last = res;
return res;
}
Tret m_last;
};
int f1() {return 1;}
double f2(int val) {return int(val) / 10.0;}
int main() {
auto f_wrapped = wrapper<f1, f2>(10);
std::cout<<f_wrapped()<<std::endl; // 10.1
std::cout<<f_wrapped()<<std::endl; // 10.2
}
This is pretty close to what I want. Only remaining issue is that I can change the argument type of f2 to something different from the return type of f1, e.g. double in the above example code and the compiler will just do a silent conversion.