For the function f(x, y, z) we can bind x to 0, getting the function g(y, z) == f(0, y, z) . We can continue this and get h() = f(0, 1, 2) .
In C ++ syntax, which will be
#include <functional> #include <iostream> void foo(int a, long b, short c) { std::cout << a << b << c << std::endl; } int main() { std::function<void(int, long, short)> bar1 = foo; std::function<void(long, short)> bar2 = std::bind(bar1, 0, std::placeholders::_1, std::placeholders::_2); std::function<void(short)> bar3 = std::bind(bar2, 1, std::placeholders::_1); std::function<void()> bar4 = std::bind(bar3, 2); bar4(); // prints "012" return 0; }
So far so good.
Now say that I want to do the same thing - bind the first argument to the function, return the new function and repeat this process until all the arguments are bound, but generalize it to work not only with function 3 as in the above example C ++, but with a function with an unknown * number of arguments.
* In C ++, there is such a thing as variable arguments, and in C ++ 11 there are variable templates. I mean the variable patterns here.
Basically, what I want to do is to write a function that takes any std::function and recursively binds the first argument to some value until all arguments are bound and the function can be called.
For simplicity, suppose std::function is a function that takes any integral arguments and returns void.
This code can be considered as a generalization of the previous code.
#include <functional> #include <iostream> // terminating case of recursion void apply(std::function<void()> fun, int i) { fun(); } template<class Head, class... Tail> void apply(std::function<void(Head, Tail...)> f, int i) { std::function<void(Tail...)> g = std::bind(f, i); apply<Tail...>(g, ++i); } void foo(int a, long b, short c) { std::cout << a << b << c << std::endl; } int main() { std::function<void(int, long, short)> bar1 = foo; apply<int, long, short>(bar1, 0); return 0; }
This code is wonderful. This is exactly what I want. It does not compile.
main.cpp: In instantiation of 'void apply(std::function<void(Head, Tail ...)>, int) [with Head = int; Tail = {long int, short int}]': main.cpp:24:40: required from here main.cpp:12:56: error: conversion from 'std::_Bind_helper<false, std::function<void(int, long int, short int)>&, int&>::type {aka std::_Bind<std::function<void(int, long int, short int)>(int)>}' to non-scalar type 'std::function<void(long int, short int)>' requested std::function<void(Tail...)> g = std::bind(f, i); ^
The problem is that you cannot just leave the call to std::placeholders in std::bind like that. They are required, and the number of placeholders in std::bind should match the number of unbound arguments in the function.
If we change the line
std::function<void(Tail...)> g = std::bind(f, i);
to
std::function<void(Tail...)> g = std::bind(f, i, std::placeholders::_1, std::placeholders::_2);
we see that it successfully passes through the first call to apply() , but gets stuck on the second pass, because during the second pass g only one placeholder is needed, while we still have two of them in std::bind .
main.cpp: In instantiation of 'void apply(std::function<void(Head, Tail ...)>, int) [with Head = long int; Tail = {short int}]': main.cpp:13:30: required from 'void apply(std::function<void(Head, Tail ...)>, int) [with Head = int; Tail = {long int, short int}]' main.cpp:24:40: required from here main.cpp:12:102: error: conversion from 'std::_Bind_helper<false, std::function<void(long int, short int)>&, int&, const std::_Placeholder<1>&, const std::_Placeholder<2>&>::type {aka std::_Bind<std::function<void(long int, short int)>(int, std::_Placeholder<1>, std::_Placeholder<2>)>}' to non-scalar type 'std::function<void(short int)>' requested std::function<void(Tail...)> g = std::bind(f, i, std::placeholders::_1, std::placeholders::_2); ^
There is a way to solve this using regular non-invariant templates, but it introduces a limit on the number of arguments to std::function . For example, this code only works if std::function has 3 or less arguments
(replace the apply functions in the previous code with them)
// terminating case void apply(std::function<void()> fun, int i) { fun(); } template<class T0> void apply(std::function<void(T0)> f, int i) { std::function<void()> g = std::bind(f, i); apply(g, ++i); } template<class T0, class T1> void apply(std::function<void(T0, T1)> f, int i) { std::function<void(T1)> g = std::bind(f, i, std::placeholders::_1); apply<T1>(g, ++i); } template<class T0, class T1, class T2> void apply(std::function<void(T0, T1, T2)> f, int i) { std::function<void(T1, T2)> g = std::bind(f, i, std::placeholders::_1, std::placeholders::_2); apply<T1, T2>(g, ++i); }
But the problem with this code is that I would have to define a new apply function to support std::function with 4 arguments, the same with 5 arguments 6 and so on. Not to mention that my goal was not to have a hard limit on the number of arguments. So this is unacceptable. I do not want him to have a limit.
I need to find a way to make the code of the variational pattern (the second code fragment) work.
If only std::bind not required to specify placeholders, then everything will work, but as std::bind works at the moment, we need to find a way to specify the correct number of placeholders.
Perhaps it would be useful to know that we can find the right amount of placeholders to indicate with C ++ 11 sizeof...
sizeof...(Tail)
but I couldnโt get anything useful from it.