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...

3
  • Will lambdas work for you? Commented Oct 12, 2018 at 6:03
  • 1
    @HolyBlackCat I'll retag with 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. Commented Oct 12, 2018 at 6:06
  • Just recently I stumbled upon boost::hof::decorate which looks as if it would also solve the problem. Commented Nov 1, 2018 at 6:26

3 Answers 3

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.

Sign up to request clarification or add additional context in comments.

Comments

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.

3 Comments

Nice, but C++17; C++11 would be much better. Mind you, there's also a boost::apply.
[](auto x, auto y) is also C++14. @KenY-N note that this is really easy in C++14; are you sure you are only C++11?
@Yakk-AdamNevraumont The project has lots of files that need tweaking, and I'm not sure if our main 3rd-party library is 100% C++14-ready.
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();
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.