Boost: bind/function index placeholder implementation

Source: Internet
Author: User

Boost: bind/function index placeholder implementation

Note: do not be surprised if the boost library is incorrectly used in the Code (for example, case does not match, or even characters are lost. This article is only used for explanation. Please use them as pseudo code.

The so-called index placeholder refers to an object that can act as an index when the BIND is executed and the input parameter is not a specific value, this object can obtain corresponding values from the real parameters passed to the function call (the function object returned by the BIND function), for example:
Int callback (int A, int B) {return a + B ;}
Int result1 = BIND (callback, 10, _ 1) (20); // callback (10, 20)
Int result2 = BIND (callback, _ 2, _ 1) (20, 10); // callback (10, 20)
In the above expression, _ 1 and _ 2 are placeholders. For int result2 = BIND (callback, _ 2, _ 1) (20, 10); (20, 10 ), 20 The index in the real parameter is and the index in the real parameter is 2. That is to say, the real parameter index is the order of the real parameters, but the order starts from 1. _ 1 indicates a real parameter with a sequential number of 1, and _ 2 indicates a real parameter with a sequential number of 2. Therefore, in int result2 = BIND (callback, _ 2, _ 1) (20, 10);, _ 1 corresponds to 20 in (20, 10, _ 2 corresponds to 10 in (20, 10.
Then, how does _ 1 and _ 2 index?
Let's take a look at the definitions of _ 1 and _ 2 (these are personal definitions, not from boost, but similar to boost ):
Template <int index> struct tindex {};
Typedef tindex <1> _ 1;
Typedef tindex <2> _ 2;
We can see that _ 1 and _ 2 are types. However, note that bind in BIND (callback, _ 2, _ 1) accepts the _ 1 and _ 2 objects, instead of the _ 1 and _ 2 types, it is equivalent:
_ 2 index2;
_ 1 index1;
BIND (index2, index1 );
As mentioned in the previous article, the return value of BIND is a function object. For int result2 = BIND (callback, _ 2, _ 1) (20, 10); bind in this expression, the return value type is similar:
Class tboundfunctionobject
{
Public:
Int operator () (int A, int B)
{
Int parameter1 = valuefromindex (m_index1inparameters, A, B );
Int parameter2 = valuefromindex (m_index2inparameters, A, B );
Return m_callback (parameter1, parameter2 );
}
PRIVATE:
INT (* m_callback) (int A, int B );
Tindex <2> m_index1inparameters;
Tindex <1> m_index2inparameters;
};
Refer to the previous article and change it to a template:
Template <typename treturn, typename targ1, typename targ2, typename tindex1, typename tindex2> class tboundfunctionobject
{
Public:
Treturn operator () (targ1 A, targ2 B)
{
Targ1 parameter1 = valuefromindex (m_index1inparameters, A, B );
Targ2 parameter2 = valuefromindex (m_index2inparameters, A, B );
Return m_callback (parameter1, parameter2 );
}
PRIVATE:
Treturn (* m_callback) (targ1 A, targ2 B );
Tindex1 m_index1inparameters;
Tindex2 m_index2inparameters;
};
The difference is that this template adds the template parameters tindex1 and tindex2 representing the index placeholder type. In fact, this is not complete, because what is passed to the BIND can be an index placeholder or an actual value. To this end, slightly change the template above:
Template <typename treturn, typename targ1, typename targ2, typename tbind1, typename tbind2> class tboundfunctionobject
{
Public:
Treturn operator () (targ1 A, targ2 B)
{
Targ1 parameter1 = valuefromindex (m_bind1, A, B );
Targ2 parameter2 = valuefromindex (m_bind2, A, B );
Return m_callback (parameter1, parameter2 );
}
PRIVATE:
Treturn (* m_callback) (targ1 A, targ2 B );
Tbind1 m_bind1;
Tbind2 m_bind2;
};
Tbind1 can be either an actual value or a value of _ 1 or _ 2.
Now, the key point is how valuefromindex is implemented?
It is certain that valuefromindex is a function template, and its return value is determined by its first parameter:
If it is an actual value, the actual value is returned;
If it is _ 1, the second parameter A is returned;
If it is _ 2, the third parameter B is returned.
Its implementation should be similar:
Template <typename targ1, typename targ2, typename targ3> treturn valuefromindex (targ1 A1, targ2 A2, targ3 A3)
{
If (isparameter (A1) return A1;
If (is_1 (A1) return A2;
If (is_2 (A1) return A3;
Throw exception ("invalid A1 .");
}
Question:
1. How to define treturn?
2. If targ2, targ3, and targ1 are different, the above implementation is obviously invalid because a function cannot have multiple return value types. So how can we solve this problem?
Of course, there are two solutions to the problem. You need to use the template meta-programming.
Do we know the three-object operator? :, But it cannot be applied to the type. If in boost: MPL, this function is implemented:
Boost: MPL: If <bool, type1, type2 >:: type: if the first parameter is true, type indicates type1; otherwise, type2.
Implementation principle (using special features ):
Template <bool T1, typename type1, typename type2> struct if
{
Typedef type1 type;
};
Template <typename type1, typename type2> struct If <false>
{
Typedef type2 type;
};
You can also use the special feature to implement the switch type function:
Switch <int I, Char, short, int >:: type: If I is 1, type indicates short; if it is 2, type indicates int; otherwise (default ), type indicates char.
Template <int I, typename type1, typename type2, typename type3> struct Switch
{
Typedef type1 type;
};
Template <typename type1, typename type2, typename type3> struct switch <1>
{
Typedef type2 type;
};
Template <typename type1, typename type2, typename type3> struct switch <2>
{
Typedef type3 type;
};
Following the switch, the first problem is solved. The treturn should be defined as follows:
Tswitch <tbind, targ1, targ2 >:: type
Template <typename tbind, typename targ1, typename targ2> struct tswitch
{
Typedef tbind type;
};
Template <typename targ1, typename targ2> struct tswitch <_ 1>
{
Typedef targ1 type;
};
Template <typename targ1, typename targ2> struct tswitch <_ 2>
{
Typedef targ2 type;
};
For the second question, the method is similar:
Template <typename targ1, typename targ2, typename targ3> tswitch <targ1, targ2, targ3 >:: type valuefromindex (targ1 A1, targ2 A2, targ3 A3)
{
Return A1;
}
Template <typename targ2, typename targ3> tswitch <_ 1, targ2, targ3 >:: type valuefromindex (_ 1 A1, targ2 A2, targ3 A3)
{
Return A2;
}
Template <typename targ2, typename targ3> tswitch <_ 2, targ2, targ3 >:: type valuefromindex (_ 2 A1, targ2 A2, targ3 A3)
{
Return A3;
}
However, it is a pity that template functions do not support special features, so you need to wrap them:
Template <typename targ1, typename targ2, typename targ3> struct valuefromindex
{
Static tswitch <targ1, targ2, targ3 >:: type value (targ1 A1, targ2 A2, targ3 A3)
{
Return A1;
}
};
Template <typename targ2, typename targ3> struct valuefromindex <_ 1>
{
Static tswitch <_ 1, targ2, targ3 >:: type value (_ 1 A1, targ2 A2, targ3 A3)
{
Return A2;
}
};
Template <typename targ2, typename targ3> struct valuefromindex <_ 2>
{
Static tswitch <_ 2, targ2, targ3 >:: type value (_ 2 A1, targ2 A2, targ3 A3)
{
Return A3;
}
};
Modify tboundfunctionobject accordingly:
Template <typename treturn, typename targ1, typename targ2, typename tbind1, typename tbind2> class tboundfunctionobject
{
Public:
Treturn operator () (targ1 A, targ2 B)
{
Targ1 parameter1 = valuefromindex <tbind1, targ1, targ2 >:: value (m_bind1, A, B );
Targ2 parameter2 = valuefromindex <tbind2, targ1, targ2 >:: value (m_bind2, A, B );
Return m_callback (parameter1, parameter2 );
}
PRIVATE:
Treturn (* m_callback) (targ1 A, targ2 B );
Tbind1 m_bind1;
Tbind2 m_bind2;
};
Finally, you must note that the number of parameters that can be accepted by tboundfunctionobject: Operator () must change with the number of actual values passed to the bind, for example:
Int result1 = BIND (callback, 10, _ 1) (20); // tboundfunctionobject: Operator () must accept 1 parameter
Int result2 = BIND (callback, _ 2, _ 1) (20, 10); // boundfunctionobject: Operator () must accept 2 parameters
Int result2 = BIND (callback, _ 2, _ 2) (20, 10); // boundfunctionobject: Operator () must accept two parameters (this does not comply with the boost rules, skip _ 1 and use _ 2 directly)
A simple solution is to reload operator (), list all possible situations, and then make corresponding judgments in various situations.
Template <typename treturn, typename targ1, typename targ2, typename tbind1, typename tbind2> class tboundfunctionobject
{
Public:
Treturn operator () // BIND (callback, 10, 20 )();
{
Assert (tmaxindex <tbind1, tbind2 >:: value = 0 );
Return m_callback (m_bind1, m_bind2 );
}
Template <tpyename targ> treturn operator () (targ A) // BIND (callback, 10, _ 1) (20); BIND (callback, _ 1, 20) (10); BIND (callback, _ 1, _ 1) (20 );
{
Assert (tmaxindex <tbind1, tbind2 >:: value = 1 );
Targ1 parameter1 = valuefromindex2 <tbind1, targ >:: value (m_bind1, );
Targ2 parameter2 = valuefromindex2 <tbind2, targ >:: value (m_bind2, );
Return m_callback (parameter1, parameter2 );
}
Treturn operator () (targ1 A, targ2 B) // BIND (callback, _ 2, _ 1) (20, 10); BIND (callback, _ 2, _ 2) (20, 10 );
{
// If you want to disable BIND (callback, _ 2, _ 2) (20, 10);, you can add assert. However, this writing method is too cumbersome. For better methods, refer to the next article.
// Assert (tmaxindex <tbind1 >:: value ==1 & tmaxindex <tbind1 >:: value = 2) | (tmaxindex <tbind1> :: value = 2 & tmaxindex <tbind1>: value = 1 ));
Assert (tmaxindex <tbind1, tbind2 >:: value = 2 );
Targ1 parameter1 = valuefromindex <tbind1, targ1, targ2 >:: value (m_bind1, A, B );
Targ2 parameter2 = valuefromindex <tbind2, targ1, targ2 >:: value (m_bind2, A, B );
Return m_callback (parameter1, parameter2 );
}
};
Valuefromindex2 is similar to valuefromindex, but only two parameters are accepted: if the first parameter is _ 1, the second parameter is returned; otherwise, the first parameter is returned.
Tmaxindex <>: used to obtain the maximum value of the largest placeholder. For example, tmaxindex <_ 1, _ 3, _ 2 >:: value is 3; tmaxindex <sometype >:: value is 0.
Tmaxindex implementation:
Template <bool B, int I1, int I2> struct ifvalue
{
Enum enumvalue {value = I1 };
};
Template <int I1, int I2> struct ifvalue <false>
{
Enum enumvalue {value = I2 };
};
Template <int I1, int I2> struct Tmax: Public ifvalue <(I1> I2), i1, I2>
{
};

// One parameter version of tmaxindex
Template <typename tType> struct tmaxindex1
{
Enum enumvalue {value = 0 };
};
Template <> struct tmaxindex1 <_ 1>
{
Enum enumvalue {value = 1 };
};
Template <> struct tmaxindex1 <_ 2>
{
Enum enumvalue {value = 2 };
};
// Tmaxindex of Two Parameter versions
Template <typename ttype1, typename ttype2> struct tmaxindex2
{
Enum enumvalue {value = Tmax <tmaxindex1 <ttype1 >:: value, tmaxindex1 <ttype2 >:: value;
};
// Tmaxindex of the three parameter versions
Template <typename ttype1, typename ttype2, typename ttype3> struct tmaxindex3
{
Enum enumvalue {value = Tmax <tmaxindex2 <ttype1, ttype2 >:: value, tmaxindex1 <ttype3 >:: value;
};
// Tmaxindex of four parameter versions
Template <typename ttype1, typename ttype2, typename ttype3, typename ttype4> struct tmaxindex4
{
Enum enumvalue {value = Tmax <tmaxindex3 <ttype1, ttype2, ttype3 >:: value, tmaxindex1 <ttype4 >:: value;
};
The above tboundfunctionobject is not good enough: Operator () with an incorrect number of called parameters cannot be detected during compilation; in this case, assert (tmaxindex <tbind1, tbind2> :: value = 0); change to boost_static_assert (tmaxindex <tbind1, tbind2 >:: value = 0.
If operator () cannot be reloaded, how can this problem be solved? Let us think about it. If you have no clue, refer to the following articles.

 

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.