0

Given boost::bind or the std:: equivalents, I can make this:

int f(int a, int b)
{
    return a + b;
}

auto f_two = boost::bind(f, 1, 1);

So that f_two() will return 2 by effectively calling an intermediate function that calls f(1, 1) via whatever implementation mechanism, perhaps something along the lines of:

double f_two_caller()
{
     return f(stored_arg_1, stored_arg_2);
}

However, my use case is that I would want to bind a prefix function so instead I could say:

auto f_print = boost::bind(printf, "Hello, world!\n");
auto f_print_and_two = boost::bind_with_prefix(f, f_print, 1, 1);

So f_print_and_two() effectively executes:

double f_print_and_two_caller()
{
    f_print(f_print.stored_arg_1);
    return f(stored_arg_1, stored_arg_2);
}

I'm sure there's a proper name for this technique that I could use to look up the solution, but I can't think of it right now...

Ken Y-N
  • 14,644
  • 21
  • 71
  • 114
  • Will [lambdas](https://en.cppreference.com/w/cpp/language/lambda) work for you? – HolyBlackCat Oct 12 '18 at 06:03
  • 1
    @HolyBlackCat I'll retag with [tag:c++11] as I can go that high but not higher, so lambdas may work. Note that `f()` can not be modified and I want to wrap up the final solution as a mixin class or the like. – Ken Y-N Oct 12 '18 at 06:06
  • Just recently I stumbled upon [`boost::hof::decorate`](https://www.boost.org/doc/libs/1_68_0/libs/hof/doc/html/include/boost/hof/decorate.html) which looks as if it would also solve the problem. – Ken Y-N Nov 01 '18 at 06:26

3 Answers3

1

I think from your description, this is what you're looking for:

#include <cstdio>
#include <tuple>
#include <utility>
#include <functional>

template<class F, class PrefixF, class...Args>
auto wrap_call_prefix(F&& f, PrefixF&& pf, Args&&...args)
{
    return [f = std::forward<F>(f), 
            pf = std::forward<PrefixF>(pf),
            args = std::make_tuple(std::forward<Args>(args)...)]
            {
                pf();
                return std::apply(f, args);
            };
}

int main()
{
    auto add = [](auto x, auto y) { return x + y; };
    auto f_print = std::bind(printf, "Hello, world!\n");

    auto f_print_and_two_caller = wrap_call_prefix(add, f_print, 1, 2);

    printf("%d\n", f_print_and_two_caller());
}

std::apply is c++17.

Richard Hodges
  • 68,278
  • 7
  • 90
  • 142
1
template<class First, class Second>
struct compose_t {
    First first;
    Second second;
    template<class...Args>
    auto operator()(Args&&...args)
    -> decltype( std::declval<Second&>()( std::declval<First&>()( std::declval<Args>()... ) ) )
    { return second(first( std::forward<Args>(args)... ) ); }
};
template<class First, class Second>
compose_t<typename std::decay<First>::type, typename std::decay<Second>::type>
compose( First&& first, Second&& second ){ return {std::forward<First>(first), std::forward<Second>(second)}; }

this is functional composition.

auto f_print = std::bind(printf, "Hello, world!\n");

auto f_print_and_two = std::bind( compose(f, f_print), 1, 1 );

int main() {
    f_print_and_two();
}

and done.

Note that function composition can be chained. You can even write a variardic compose function based on the above.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
0

If I were you, I would not replicate bind functionality and just go for something like this, which is pretty straightforward:

template<class Pre, class U>
class with_prefix_class{
public:
    template<class V, class W>
    with_prefix_class(V &&v, W &&w) : pre_(std::forward<V>(v)), func_(std::forward<W>(w)){}

    decltype(std::declval<U>()()) operator()(){
        pre_();
        return func_();
    }

private:
    Pre pre_;
    U func_;
};

int f(int a, int b)
{
    return a + b;
}

template<class Pre, class U>
with_prefix_class<Pre, U> with_prefix(Pre &&pre, U &&u){
    return with_prefix_class<Pre, U>(std::forward<Pre>(pre), std::forward<U>(u));
}

int main(int argc, char* argv[]) {
    auto a = with_prefix([](){}, std::bind(f, 5, 3));
    a();
}
bartop
  • 9,971
  • 1
  • 23
  • 54