Have you noticed that all function objects in C ++ are in the form of passing values? -Boost: Powerful use of ref ~

Source: Internet
Author: User

 

If you use the STL algorithm frequently, you will notice that the function object is passed in the form of passing values as follows: sort, for_each, _ Compare _ comp instead of _ Compare & _ comp.

template<typename _RandomAccessIterator, typename _Compare>    inline void    sort(_RandomAccessIterator __first, _RandomAccessIterator __last,     _Compare __comp)    {    }
template<typename _InputIterator, typename _Function>    _Function    for_each(_InputIterator __first, _InputIterator __last, _Function __f)    {      // concept requirements      __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>)      __glibcxx_requires_valid_range(__first, __last);      for ( ; __first != __last; ++__first)    __f(*__first);      return __f;    }

Are you confused here? Why do we need to pass the reference in the form of passing values? After all, a major advantage of a function object that distinguishes itself from a function pointer is that it can carry state variables. For example, the following function object contains a state variable a. In fact, it can contain more complex and memory-occupied variables, therefore, the method of transferring values must have a high copy cost.

struct Func{    int a;    Func()    : a(0)    {    }    void operator()(int x)    {        add(x);    }    void add(int x)    {        cout << "a: " << a << endl;        cout << "this: " << this << endl;        cout << "add " << x << endl;        a += x;    }};
Another thing is that we can change the value of a in the following state variables by referencing them. If we want to pass the reference method, we want the passed Func () it can be used by other functions and change its state after being passed to other functions. After other functions are used, its state may change.
For example, I wrote an encapsulation for reading the database from OTL.
Template <typename Func> void process (Func func) {// process (func); LOG (INFO) <Pval (SQL) <"\ n "; try {otl_stream OS (1024, SQL. c_str (), conn); // connect to the database and read the data func (OS); OS. flush ();} catch (otl_exception & p) {// intercept OTL exceptions cerr <p. msg <endl; // print out error message cerr <p. pai_text <endl; // print out SQL that caused the error cerr <p. sqlstate <endl; // print out SQLSTATE message cerr <p. var_info <endl; // print out the variable that caused the error }}

Now I have an application that reads words from the database and counts popular words,

struct ReadFunc{    typedef std::deque<Node> Deque;    typedef std::priority_queue<Node, Deque, std::greater<Node> > PQueue;    typedef std::tr1::unordered_map<string, int> HashMap;    HashMap hash_map;    PQueue m_pqueue;    ch_convert::ChConverter m_converter;    long long m_keyNum;    long long m_keyCount;    template<typename Stream>            void operator()(Stream & os)    {        string key;        int count;        int line_num = 0;        long long key_count = 0;        boost::array<char, 2 > seperator = {' ', '\t'};        while (!os.eof())        {            os >> key >> count;           …         }     }

Now the problem is coming. See below

Void run () {// keyword statistics for normal condition LOG (INFO) <"Normal run" <endl; ReadFunc reader; run _ (reader ); // m_dbreader.process (reader) in the function. Here I want m_queue in reader to record the popular buzzword to be changed! If the value is passed... Oh my god !!!! Finalize _ (reader );}

So why does STL use the value transfer method ?? What about passing function objects ??? I think it is for the following reasons:

Std: sort (begin, end, Cmp ());

Have you seen it? It is very common to pass a temporary function object !! I only need a line of code. If it is the form of transferring references _ Compare & _ comp, sorry, you cannot write this because temporary objects cannot be passed references...

You want to write

Cmp cmp;

Std: sort (begin, end, cmp );

It's very troublesome, right? I still hope there is a way to get the best of both worlds by referencing?

There is a work around und that is passed by const reference. This can be used to pass temporary variables.

Template <typename _ RandomAccessIterator, typename _ Compare> inline void sort (_ RandomAccessIterator _ first, _ RandomAccessIterator _ last, const _ Compare & _ comp ){}

This method is also a trial of the popular statistical terms I mentioned above. I can pass the reference and change the internal state of my reader, but the compiler is a bit unhappy, it will warning because you are a const statement and you have removed its const ....

The C ++ standard encourages us to do this. The for_each and Other interfaces are all written by passing values... If you use those interfaces, you cannot upload references?

Solve all the problems with boost: ref and kaka.

Template <typename T> void sort (T func) {func (3);} Func func; func (1); cout <"func. a: "<func. a <endl; // 1 sort (boost: bind <void> (boost: ref (func), _ 1); cout <"func. a: "<func. a <endl; // 4 // The status has changed. We passed the reference ~
 
Note that the C ++ standard tr1 has also been implemented, such as ref, bind, and function, but I haven't fully understood it yet. It seems that compilation is not possible to solve the problem, so it is recommended to use boost for the time being... Haha
 
Note about bind
 

Http://aszt.inf.elte.hu /~ Gsd/halado_cpp/ch11.html

Boost: bind is a generalization of the standard functions std: bind1st and std: bind2nd. it supports arbitrary function objects, functions, function pointers, and member function pointers, and is able to bind any argument to a specific value or route input arguments into arbitrary positions. bind does not place any requirements on the function object; in particle, it does not need the result_type, first_argument_type and second_argument_type standard typedefs.

Example:

Int f (int a, int B)
{
Return a + B;
}

Int g (int a, int B, int c)
{
Return a + B + c;
}

Usage of bind

Bind (f, 1, 2) will produce a "nullary" function object that takes no arguments and returns f (1, 2 ). similarly, bind (g, 1, 2, 3) () is equivalent to g (1, 2, 3 ).

It is possible to selectively bind only some of the arguments.

Bind (f, _ 1, 5) (x)/* is equivalent to */f (x, 5)

Here _ 1 is a placeholder argument that means "substitute with the first input argument ."

The same with the older version:

Std: bind2nd (std: ptr_fun (f), 5) (x );

More complex solutions:

Bind (f, _ 2, _ 1) (x, y); // f (y, x)
Bind (g, _ 1, 9, _ 1) (x); // g (x, 9, x)
Bind (g, _ 3, _ 3, _ 3) (x, y, z); // g (z, z, z)
Bind (g, _ 1, _ 1, _ 1) (x, y, z); // g (x, x)

Note that, in the last example, the function object produced by bind (g, _ 1, _ 1, _ 1) does not contain references to any arguments beyond the first, but it can still be used with more than one argument. any extra arguments are silently ignored, just like the first and the second argument are ignored in the third example.

The argumenst are copies. If we want to use references, we need helper functions:

Int I = 5;

Bind (f, I, _ 1 );
Bind (f, ref (I), _ 1 );

Function objects

The bind is not limited to functions; it accepts arbitrary function objects. in the general case, the return type of the generated function object's operator () has to be specified explicitly (without a typeof operator the return type cannot be inferred ):

Struct F
{
Int operator () (int a, int B) {return a-B ;}
Bool operator () (long a, long B) {return a = B ;}
};

F f;

Int x = 104;
Bind <int> (f, _ 1, _ 1) (x); // f (x, x), I. e. zero

Int x = 8;
Bind (std: less <int> (), _ 1, 9) (x); // x <9

Example

Class image;

Class animation
{
Public:

Void advance (int MS );
Bool inactive () const;
Void render (image & target) const;
};

Std: vector <animation> anims;

Template <class C, class P> void erase_if (C & c, P pred)
{
C. erase (std: remove_if (c. begin (), c. end (), pred), c. end ());
}

Void update (MS int)
{
Std: for_each (anims. begin (), anims. end (), boost: bind (& animation: advance, _ 1, MS ));
Erase_if (anims, boost: mem_fn (& animation: inactive ));
}

Void render (image & target)
{
Std: for_each (anims. begin (), anims. end (), boost: bind (& animation: render, _ 1, boost: ref (target )));
}

Reference wrapper

The header boost/ref. hpp defines the class template boost: reference_wrapper <T>, the two functions boost: ref and boost: cref that return instances of boost: reference_wrapper <T>, and the two traits classes boost: is_reference_wrapper <T> and boost: unwrap_reference <T>.

The purpose of boost: reference_wrapper is to contain a reference to an object of type T. it is primarily used to "feed" references to function templates (algorithms) that take their parameter by value.

To support this usage, boost: reference_wrapper provides an implicit conversion to T &. This usually allows the function templates to work on references unmodified.

Namespace boost
{
Template <class T> class reference_wrapper;
Template <class T> reference_wrapper <T> ref (T & t );
Template <class T> reference_wrapper <T const> cref (T const & t );
Template <class T> class is_reference_wrapper <T const>;
Template <class T> class unwrap_reference <T const>;
}

Implementation is trivial

Template <class T> class reference_wrapper
{
Public:
Typedef T type;
Explicit reference_wrapper (T & t );

Operator T & () const;

T & get () const;
T * get_pointer () const;
Private:
T * t _;
};

Prev Up Next
Define your own streambuffer Home Tuple

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.