1

Is it somehow possible to easily mimic std::bind_front in C++17 ? (just for member function wrapping is fine)

I took a look at implementation in aiming to copy but it seems its very much implementation specific indeed.

I'm thinking a lambda wrapper or template function/object might work?

(Performance is not an issue here)

cigien
  • 57,834
  • 11
  • 73
  • 112
darune
  • 10,480
  • 2
  • 24
  • 62
  • Yes, it's possible. Could go with lambda, or a dedicated class with bound args stored in a tuple, for instance. – bipll Nov 06 '20 at 10:42

3 Answers3

4

This can be a starting point

template<typename F, typename ...FrontArgs>
struct bindfronthelper
{
    bindfronthelper(F f, FrontArgs&&...args)
        : mF{std::move(f)}
        , mFrontArg{std::forward<FrontArgs>(args)...}
    {}

    template<typename ...BackArgs>
    auto operator()(BackArgs&&...args) const
    {
        return std::apply(mF, std::tuple_cat(mFrontArg, std::forward_as_tuple(args...)));
    }

    F mF;
    std::tuple<std::decay_t<FrontArgs>...> mFrontArg;
};

template<typename F, typename ...FrontArgs>
auto mybindfront(F f, FrontArgs&&...args)
{
    return bindfronthelper<F, FrontArgs...>{std::move(f), std::forward<FrontArgs>(args)...};
}

https://godbolt.org/z/Tz9fen

Written quickly and not tested well, so there might be some pitfalls in corner cases. At least it shows how this can be achieved.


Ok I made this over complicated, here is simpler version:

template<typename T, typename ...Args>
auto tuple_append(T&& t, Args&&...args)
{
    return std::tuple_cat(
        std::forward<T>(t),
        std::forward_as_tuple(args...)
    );
}

template<typename F, typename ...FrontArgs>
decltype(auto) mybindfront(F&& f, FrontArgs&&...frontArgs)
{
    return [f=std::forward<F>(f), 
            frontArgs = std::make_tuple(std::forward<FrontArgs>(frontArgs)...)]
            (auto&&...backArgs) 
        {
            return std::apply(
                f, 
                tuple_append(
                    frontArgs, 
                    std::forward<decltype(backArgs)>(backArgs)...)); 
        };
}

https://godbolt.org/z/cqPjTY

still passes all test I've provided. I'm keeping old version since with a bit of work it can be tweaked to work with older standard of c++.

Marek R
  • 32,568
  • 6
  • 55
  • 140
  • 1
    Caveat is value categories, first keeps reference instead of copying. Lamdba does copy and not move for capture. – Jarod42 Nov 06 '20 at 13:36
0

One really simpel way I found is with lambda's (in this case capturing this - but you can change that easily to be generally adoptable):

auto bind_m = [this](auto mem_f) {
    auto wrapper = [=] (auto&&... args) {return std::mem_fn(mem_f)(this, std::forward<decltype(args)>(args)...);};
    return wrapper;
};

The lambda creates another lambda and returns it.

darune
  • 10,480
  • 2
  • 24
  • 62
0
template<typename F, typename... FRONT_ARGS>
    auto bind_front(F&& f, FRONT_ARGS&&... front_args)
    {
        // front_args are copied because multiple invocations of this closure are possible
        return [captured_f = std::forward<F>(f), front_args...](auto&&... back_args) {
                   return std::invoke(captured_f, front_args...,
                                      std::forward<decltype(back_args)>(back_args)...);
               };
    }
Mikhail Kupchik
  • 308
  • 2
  • 8