Std: Inside the bind Technology

Source: Internet
Author: User

Introduction

Recently, the group is very lively. Everyone is in the std: bind of c ++ 11. The three children have implemented their own bind, and the code is here:

  • Wood cloud implementation: http://sourceforge.net/projects/foobar-dummy/files/bind/
  • Implementation of mr. li: https://code.google.com/p/y-code-svn/source/browse/#svn%2Ftrunk%2Fc%2B%2B%2FBex%2Fsrc%2FBex%2Fbind
  • Implementation of null: http://www.cnblogs.com/xusd-null/p/3693817.html#2934538

These Implementation ideas are similar to the std: bind Implementation ideas of ms stl, but they are somewhat different in the implementation details. I personally think that the implementation of wood cloud is more concise. The simple implementation in this article is based on the bind of wood cloud. I would like to express my gratitude here. Next we will analyze the basic principles of bind.

Basic Principles of bind

The idea of bind is actually a method of delayed computing. It saves callable objects and calls them as needed. In addition, this binding is very flexible. Both common functions, function objects, and member functions can be bound, and its parameters can support placeholders, for example, you can bind a binary function auto f = bind (& func, _ 1, _ 2); and call it through f (1, 2. For more information about bind usage, see my blog: http://www.cnblogs.com/qicosmos/p/3302144.html.

To implement a bind, you need to solve two problems. The first is to save the callable object and its parameters, and the second is how to implement the call. The following describes how to solve these two problems.

Save callable object

To implement bind, the first problem to be solved is how to save the callable object so that it can be called later. To save a callable object, you need to save two things: one is the instance of callable object, and the other is the parameter of callable object. It is very easy to save the instance of the callable object, because bind directly needs to pass this callable object and use it as a member variable. However, it is a little effort to save the variable object parameters because the variable parameter is a variable and cannot be directly used as a member variable. To save the variable parameters, we need to use tuple to save the variable parameters.

Invocation of callable objects

Because bind parameters are variable parameters, they can be zero or multiple. In most cases, they are placeholders, and they can also be placeholders and real parameters. It is precisely because of the flexibility of bind binding that we have to find out which are placeholders and real parameters during the call. If a parameter is a real parameter, we will not process it. If it is a placeholder, we will replace this placeholder with the corresponding real parameter. For example, we bound a ternary function: auto f = bind (& func, _ 1, 2, _ 2); f () during the call; because there are three parameters when binding, one real parameter, two placeholders. Two real parameters are input during the call. In this case, we need to replace placeholder _ 1 with real parameter 1, and placeholder _ 2 with real parameter 3. The placeholder must be replaced by calling the real parameters. If the number of real parameters in the call is greater than that of the placeholder, the excess real parameters are ignored.
We will first convert the called real parameters to tuple, which is used to select the appropriate real parameters when the placeholder is replaced later.

The key technology of bind implementation expands tuple into variable parameters

As mentioned above, when binding callable objects, save the parameters (which may contain placeholders) of callable objects to tuple. At the call stage, we need to expand the tuple into a variable parameter in turn, because this variable parameter is the shape parameter of the callable object, otherwise the call will not be implemented. Here we will use an integer sequence to change tuple into a variable parameter. During the expansion of tuple, we also need to select the appropriate real parameter based on the placeholder, that is, the placeholder should be replaced with the called real parameter.

Select an appropriate real parameter based on the placeholder

This is critical because tuple may contain placeholders. When we expand tuple, if we find that an element type is a placeholder, We will retrieve a real parameter from the tuple generated by the called real parameter, this parameter is used as a parameter for variable parameters. When a type is not a placeholder, the parameter is taken directly from the tuple generated during binding as a parameter for variable parameters. In the end, tuple is expanded into a variable parameter list. In this case, there is no placeholder in the list, and all the parameters are real parameters, so you can call the tuple. Here is also a detail. When replacing placeholders, how can we select appropriate parameters from tuple, because they should be selected in order. Here we use the placeholder template parameter I for selection, because the placeholder place_holder <I> instance _ 1 is actually place_holder <1>, the placeholder instance _ 2 is actually palce_holder <2>, we can obtain the order based on the placeholder template parameters.

Simple bind implementation # include <tuple> # include <type_traits> using namespace std; template <int...> struct IndexTuple {}; template <int N, int... indexes> struct MakeIndexes: MakeIndexes <N-1, N-1, Indexes...> {}; template <int... indexes> struct MakeIndexes <0, indexes...> {typedef IndexTuple <indexes...> type ;}; template <int I> struct Placeholder {}; Placeholder <1> _ 1; Placeholder <2> _ 2; Placeholder <3> _ 3; Placeholder <4> _ 4; Placeholder <5> _ 5; Placeholder <6> _ 6; Placeholder <7> _ 7; Placeholder <8> _ 8; Placeholder <9> _ 9; placeholder <10> _ 10; // result type traitstemplate <typename F> struct result_traits: result_traits <decltype (& F: operator ()> {}; template <typename T> struct result_traits <T *>: result_traits <T >{};/* check function */template <typename R, typename... p> struct result_traits <R (*) (P...)> {typedef R type; };/* Check member function */template <typename R, typename C, typename... p> struct result_traits <R (C: *) (P...)> {typedef R type ;}; template <typename T, class Tuple> inline auto select (T & val, Tuple &)-> T & {return std :: forward <T> (val);} template <int I, class Tuple> inline auto select (Placeholder <I >&, Tuple & tp)-> decltype (std :: get <I-1> (tp) {return std: get <I-1> (tp);} // The invoker for cal L a callabletemplate <typename T> struct is_pointer_noref: std: is_pointer <typename std: remove_reference <T >:: type >{}; template <typename T> struct is_memfunc_noref: std:: is_member_function_pointer <typename std: remove_reference <T >:: type >{}; template <typename R, typename F, typename... p> inline typename std: enable_if <is_pointer_noref <F >:: value, R >:: type invoke (F & f, P &&... par) {return (* std: forw Ard <F> (f) (std: forward <P> (par )...);} template <typename R, typename F, typename P1, typename... p> inline typename std: enable_if <is_memfunc_noref <F >:: value & is_pointer_noref <P1 >:: value, R >:: type invoke (F & f, p1 & this_ptr, P &&... par) {return (std: forward <P1> (this_ptr)-> * std: forward <F> (f) (std :: forward <P> (par )...);} template <typename R, typename F, typename P1, typename... p> inline typename st D: enable_if <is_memfunc_noref <F >:: value &&! Is_pointer_noref <P1 >:: value, R >:: type invoke (F & f, P1 & this_obj, P &&... par) {return (std: forward <P1> (this_obj ). * std: forward <F> (f) (std: forward <P> (par )...);} template <typename R, typename F, typename... p> inline typename std: enable_if <! Is_pointer_noref <F >:: value &&! Is_memfunc_noref <F >:: value, R >:: type invoke (F & f, P &&... par) {return std: forward <F> (f) (std: forward <P> (par )...);} template <typename Fun, typename... args> struct Bind_t {typedef typename decay <Fun>: type FunType; typedef std: tuple <typename decay <Args >:: type...> argType; typedef typename result_traits <FunType>: type result_type; public: template <class F, class... BArgs> Bind_t (F & f, BArgs &... args): m_func (f), m_args (args ...) {} template <typename F, typename... BArgs> Bind_t (F & f, BArgs &&... par): m_func (std: move (f), m_args (std: move (par )...) {} template <typename... CArgs> result_type operator () (CArgs &&... args) {return do_call (MakeIndexes <std: tuple_size <ArgType >:: value >::: type (), std: forward_as_tuple (std :: forward <CArgs> (args )...));} template <typename ArgTuple, int... indexes> result_type do_call (IndexTuple <Indexes...> & in, ArgTuple & argtp) {return simple: invoke <result_type> (m_func, select (std: get <Indexes> (m_args), argtp )...); // return m_func (select (std: get <Indexes> (m_args), argtp )...);} private: FunType m_func; ArgType m_args;}; template <typename F, typename... p> inline Bind_t <F, P...> bind (F & f, P &&... par) {return Bind_t <F, P...> (std: forward <F> (f), std: forward <P> (par )...);} template <typename F, typename... p> inline Bind_t <F, P...> bind (F & f, P &... par) {return Bind_t <F, P...> (f, par ...);}View Code

Test code:

Void TestFun1 (int a, int B, int c) {} void TestBind1 () {Bind (& TestFun1, _ 1, _ 2, _ 3) (1, 2, 3); Bind (& TestFun1, 4, 5, _ 1) (6); Bind (& TestFun1, _ 1, 4, 5) (3); Bind (& TestFun1, 3, _ 1, 5) (4 );}View Codebind more Implementation Details

Because it only shows the key technology of bind implementation, many implementation details are not processed, such as whether the parameter is referenced, the right value, const volotile, and binding non-static member variables, instead of repeatedly inventing the wheel, it just shows how bind is implemented. In actual projects, it is better to use std: bind of c ++ 11. Null also illustrated the bind process: http://www.cnblogs.com/xusd-null/p/1098969.html. For more information, see.

Bind usage

In actual use, I prefer to use lambda expressions, because lambda expressions are simpler and more intuitive to use, and lambda expressions can replace bind in most cases.

 

If you think this article is useful to you, click here for recommendations. Thank you.

C ++ 11 boost technology exchange group: 296561497. You are welcome to exchange technologies.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.