8

I'd like to have a function BindFirst that binds the first argument of a function without me having to explicitly know/state the arity of the function by using std::placeholders. I'd like the client code to look something like that.

#include <functional>
#include <iostream>

void print2(int a, int b)
{
    std::cout << a << std::endl;
    std::cout << b << std::endl;
}

void print3(int a, int b, int c)
{
    std::cout << a << std::endl;
    std::cout << b << std::endl;
    std::cout << c << std::endl;
}

int main()
{ 
    auto f = BindFirst(print2, 1); // std::bind(print2, 1, std::placeholders::_1);
    auto g = BindFirst(print3, 1); // std::bind(print3, 1, std::placeholders::_1, std::placeholders::_2);
    f(2);
    g(2,3);
}

Any ideas how BindFirst could be implemented?

Piotr Skotnicki
  • 46,953
  • 7
  • 118
  • 160
Tobias Hermann
  • 9,936
  • 6
  • 61
  • 134

2 Answers2

10

In :

#include <type_traits>
#include <utility>

template <typename F, typename T>
struct binder
{
    F f; T t;
    template <typename... Args>
    auto operator()(Args&&... args) const
        -> decltype(f(t, std::forward<Args>(args)...))
    {
        return f(t, std::forward<Args>(args)...);
    }
};

template <typename F, typename T>
binder<typename std::decay<F>::type
     , typename std::decay<T>::type> BindFirst(F&& f, T&& t)
{
    return { std::forward<F>(f), std::forward<T>(t) };
}

DEMO

In :

#include <utility>

template <typename F, typename T>
auto BindFirst(F&& f, T&& t)
{
    return [f = std::forward<F>(f), t = std::forward<T>(t)]
           (auto&&... args)
           { return f(t, std::forward<decltype(args)>(args)...); };
}

DEMO 2

Piotr Skotnicki
  • 46,953
  • 7
  • 118
  • 160
  • can I know why `std::decay` is used? – billz Nov 15 '15 at 23:34
  • @billz Because here we want to store copies (possibly move-constructed) of the arguments passed to `BindFirst`. You certainly don't want to store references, neither their constness/volatileness is of your interest here. Say, for `T&&=int&&` you want to store `int` – Piotr Skotnicki Nov 16 '15 at 08:37
0

I was wondering if You can do that in C++, then I realized that simple variadic macro in C should be enough.

#include <stdio.h>

#define bindFirst(functionName, firstArgument, ...) \
        functionName(firstArgument, __VA_ARGS__)

void print2(int a, int b) {
  printf("%d %d\n", a, b);
}

void print3(int a, int b, int c) {
  printf("%d %d %d\n", a, b, c);
}

int main() {
  
    #define f(...) bindFirst(print2, 1, __VA_ARGS__)
    #define g(...) bindFirst(print3, 1, __VA_ARGS__)

    f(2);
    g(2,3);

    #undef f
    #undef g
  
    return 0;
}
user712092
  • 1,988
  • 1
  • 14
  • 16