0

I am trying to write the piece of code which will do the following: let's assume we have a call of custom bind function

auto bind_obj = bind(some_func, _1, "test")  

and after we have

auto res = bind_obj(42) 

where the function some_func:

int some_func(int val, string test)

How can it possible to match placeholders with arguments provided in actual function call, i.e. bind_obj(...)??

In other words, is it possible to iterate over std::tuple (arguments and placeholders here) and variadic pack (function arguments) to:

  1. deduce the return type of function some_func;
  2. make correct std::tuple to further use it in some_func() call ?

I am trying to do this not using boost and std::functional. I think, my main problem is that i don't understand how to build tuple at runtime with arguments (where all the placeholders replaced correctly) and to deduce return type.

I saw _Mu template structure in STL "functional.h" but it looks too complex and overloaded.

Peter Leontev
  • 107
  • 1
  • 8
  • The `` standard header is part of C++. What do you mean via "pure C++"? – Shoe May 31 '15 at 15:03
  • I want to write matching between arguments and placeholders manually (very probaly, using templates, yes) Above bind is just an example of usual use of bind-like functions – Peter Leontev May 31 '15 at 15:05
  • Sorry, i recognized the mistype, that should be bind(some_func, _1, "test") and then: bind_obj(42) – Peter Leontev May 31 '15 at 15:13
  • At least, only how to iterate over variadic pack (only function arguments here) and std::tuple (which contain function arguments and placeholders) simultaneously, to build a new tuple with function arguments in correct order – Peter Leontev May 31 '15 at 15:22

1 Answers1

2

Since the argument list of the call and list of captured arguments are differently sized, you won't really iterate over them. Instead, you'd get a function evaluated which behaves according to how arguments were captured:

  • if the bound element is a value it returns the value
  • if the bound element is a placeholder it returns the argument at the given index
  • if the bound element is a bind function it returns the result of evaluating this function

Assume your bound object contains a std::tuple<B...> of bound arguments called b then you could construct a std::tuple<...> of call arguments something like this:

template <typename... A, std::size_t... I>
... bound::call(std::tuple<A...>&& aux, index_list<I...>) {
    auto args = std::make_tuple(get_argument<I>(this->b, a));
    // ...
}
template <typename... A>
... bound::operator()(A&&... args) {
    return this->call(std::tie(std::forward<A>(args)..., make_index_list<sizeof...A>());
}

This code snippet just shows how to get the arguments sort of matched up. The real work happens in the get_argument<I>(b, a) functions which woild just return the element of a indicated by the placeholder's value if the element at index I in b happens to be a placeholder.

The code doesn't include details on how to create an index list, how to determine rhe return type once the call is sorted out, or how to deal with rvalue arguments...

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
  • Thank you! BTW, as I know we can't use auto for operator() as return type before C++ 14. Could you give a direction about how to determine the return type of the function? – Peter Leontev May 31 '15 at 16:03
  • @PeterLeontev: You are really going to call your function something along the lines of: `fun(std::make_tuple(get_argument(this->b, a))`. The type is just the `decltype(...)` of this expression. For the function call operator you'd just use the `decltype(...)` of the `call()` helper. If it refuses to use `this` in the trailing return type to get hold of `this->b` you may need to use `declval()` (with `T` being the type of `this->b`). – Dietmar Kühl May 31 '15 at 16:54
  • Thank you, again. I've tried to use this approach but why do we need to sizeof...A>? What if sizeof...B > sizeof...A? – Peter Leontev May 31 '15 at 18:10
  • 1
    You are right: the indices needed are actually _not_ for `A...` but for `B...`! Whether the corresponding size is readily available in your bound object type I wouldn't know but it should be trivial to get hold of. The sizes of `A...` and `B...` should be entirely independent. – Dietmar Kühl May 31 '15 at 20:17