c++ how to create a function wrapper?

Viewed 120

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.

0 Answers
Related