Search code examples
c++boostboost-bind

Generic function bind() with Boost


I have some C-style functions that return 0 to indicate success, and != 0 on error.
I'd like to "wrap" them into void functions that throw instead of returning a value.

I have written this helper:

void checkStatus(int status) {
  if (status != 0)
    // throw an error object
}

Then, to wrap a determinate function int tilt(float degrees), I use boost::bind:

function<void(float)> ntilt = bind(checkStatus, bind(tilt, _1));
ntilt(30); // this will call checkStatus(tilt(30))

And it works great. But I'd like to have a dedicate wrapper function, so I can just do:

function<void(float)> ntilt = wrap(tilt);
ntilt(30); // this will call checkStatus(tilt(30))

It should work for any function/signature that returns an int.
What would be the best way to do it using Boost?


Solution

  • You could create several overloads to handle the different amount of parameters that your wrapped functions might take:

    // handles 1 parameter functions
    template<typename Ret, typename T0>
    function<void(T0)> wrap(Ret (*fun)(T0)) {
        return bind(checkStatus, bind(fun, _1));
    }
    
    // handles 2 parameters functions    
    template<typename Ret, typename T0, typename T1>
    function<void(T0, T1)> wrap(Ret (*fun)(T0, T1)) {
        return bind(checkStatus, bind(fun, _1, _2));
    }
    
    // ... add more
    

    Here's a C++11 implementation. You could avoid some stuff if you didn't want an std::function, but well, it works:

    #include <functional>
    #include <stdexcept>
    
    template<typename Ret, typename... Args>
    struct wrapper {
        typedef Ret (*function_type)(Args...);
    
        void operator()(Args&&... args) {
            if(fun(std::forward<Args>(args)...) != 0)
                throw std::runtime_error("Error");
        }
    
        function_type fun;
    };
    
    template<typename Ret, typename... Ts>
    std::function<void(Ts...)> wrap(Ret (*fun)(Ts...)) {
        return std::function<void(Ts...)>(wrapper<Ret, Ts...>{fun});
    }
    

    Here is a live demo.