mirror of
https://github.com/boostorg/lambda.git
synced 2026-01-22 05:12:51 +00:00
208 lines
12 KiB
HTML
208 lines
12 KiB
HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||
<html><head><meta content="text/html; charset=ISO-8859-1" http-equiv="Content-Type"><title>6. Extending return type deduction system</title><meta name="generator" content="DocBook XSL Stylesheets V1.48"><link rel="home" href="index.html" title="
|
||
C++ BOOST
|
||
|
||
The Boost Lambda Library"><link rel="up" href="index.html" title="
|
||
C++ BOOST
|
||
|
||
The Boost Lambda Library"><link rel="previous" href="ar01s05.html" title="5. Lambda expressions in details"><link rel="next" href="ar01s07.html" title="7. Practical considerations"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">6. Extending return type deduction system</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ar01s05.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="ar01s07.html">Next</a></td></tr></table><hr></div><div class="section"><div class="titlepage"><div><h2 class="title" style="clear: both"><a name="sect:extending_return_type_system"></a>6. Extending return type deduction system</h2></div></div><p>
|
||
|
||
|
||
In this section, we explain how to extend the return type deduction system
|
||
to cover user defined operators.
|
||
|
||
In many cases this is not necessary,
|
||
as the BLL defines default return types for operators.
|
||
|
||
For example, the default return type for all comparison operators is
|
||
<tt>bool</tt>, and as long as the user defined comparison operators
|
||
have a bool return type, there is no need to write new specializations
|
||
for the return type deduction classes.
|
||
|
||
Sometimes this cannot be avoided, though.
|
||
|
||
</p><p>
|
||
The overloadable user defined operators are either unary or binary.
|
||
|
||
For each arity, there are two traits templates that define the
|
||
return types of the different operators.
|
||
|
||
Hence, the return type system can be extended by providing more
|
||
specializations for these templates.
|
||
|
||
The templates for unary functors are
|
||
|
||
<tt>
|
||
plain_return_type_1<Action, A>
|
||
</tt>
|
||
|
||
and
|
||
|
||
<tt>
|
||
return_type_1<Action, A>
|
||
</tt>, and
|
||
|
||
<tt>
|
||
plain_return_type_2<Action, A, B>
|
||
</tt>
|
||
|
||
and
|
||
|
||
<tt>
|
||
return_type_2<Action, A, B>
|
||
</tt>
|
||
|
||
respectively for binary functors.
|
||
|
||
</p><p>
|
||
The first parameter (<tt>Action</tt>) to all these templates
|
||
is the <span class="emphasis"><i>action</i></span> class, which specifies the operator.
|
||
|
||
Operators with similar return type rules are grouped together into
|
||
<span class="emphasis"><i>action groups</i></span>,
|
||
and only the action class and action group together define the operator
|
||
unambiguously.
|
||
|
||
As an example, the action type
|
||
<tt>arithmetic_action<plus_action></tt> stands for
|
||
<tt>operator+</tt>.
|
||
|
||
The complete listing of different action types is shown in
|
||
<a href="ar01s06.html#table:actions" title="Table 2. Action types">Table 2</a>.
|
||
</p><p>
|
||
The latter parameters, <tt>A</tt> in the unary case,
|
||
or <tt>A</tt> and <tt>B</tt> in the binary case,
|
||
stand for the argument types of the operator call.
|
||
|
||
The two sets of templates,
|
||
<tt>plain_return_type_<i><tt>n</tt></i></tt> and
|
||
<tt>return_type_<i><tt>n</tt></i></tt>
|
||
(<i><tt>n</tt></i> is 1 or 2) differ in the way how parameter types
|
||
are presented to them.
|
||
|
||
For the former templates, the parameter types are always provided as
|
||
non-reference types, and do not have const or volatile qualifiers.
|
||
|
||
This makes specializing easy, as commonly one specialization for each
|
||
user defined operator, or operator group, is enough.
|
||
|
||
On the other hand, if a particular operator is overloaded for different
|
||
cv-qualifications of the same argument types,
|
||
and the return types of these overloaded versions differ, a more fine-grained control is needed.
|
||
|
||
Hence, for the latter templates, the parameter types preserve the
|
||
cv-qualifiers, and are non-reference types as well.
|
||
|
||
The downside is, that for an overloaded set of operators of the
|
||
kind described above, one may end up needing up to
|
||
16 <tt>return_type_2</tt> specializations.
|
||
</p><p>
|
||
Suppose the user has overloaded the following operators for some user defined
|
||
types <tt>X</tt>, <tt>Y</tt> and <tt>Z</tt>:
|
||
|
||
<pre class="programlisting">
|
||
Z operator+(const X&, const Y&);
|
||
Z operator-(const X&, const Y&);
|
||
</pre>
|
||
|
||
Now, one can add a specialization stating, that if the left hand argument
|
||
is of type <tt>X</tt>, and the right hand one of type
|
||
<tt>Y</tt>, the return type of all such binary arithmetic
|
||
operators is <tt>Z</tt>:
|
||
|
||
<pre class="programlisting">
|
||
namespace boost {
|
||
namespace lambda {
|
||
|
||
template<class Act>
|
||
struct plain_return_type_2<arithmetic_action<Act>, X, Y> {
|
||
typedef Z type;
|
||
};
|
||
|
||
}
|
||
}
|
||
</pre>
|
||
|
||
Having this specialization defined, BLL is capable of correctly
|
||
deducing the return type of the above two operators.
|
||
|
||
Note, that the specializations must be in the same namespace,
|
||
<tt>::boost::lambda</tt>, with the primary template.
|
||
|
||
For brevity, we do not show the namespace definitions in the examples below.
|
||
</p><p>
|
||
It is possible to specialize on the level of an individual operator as well,
|
||
in addition to providing a specialization for a group of operators.
|
||
Say, we add a new arithmetic operator for argument types <tt>X</tt>
|
||
and <tt>Y</tt>:
|
||
|
||
<pre class="programlisting">
|
||
X operator*(const X&, const Y&);
|
||
</pre>
|
||
|
||
Our first rule for all arithmetic operators specifies that the return
|
||
type of this operator is <tt>Z</tt>,
|
||
which obviously is not the case.
|
||
Hence, we provide a new rule for the multiplication operator:
|
||
|
||
<pre class="programlisting">
|
||
template<>
|
||
struct plain_return_type_2<arithmetic_action<multiply_action>, X, Y> {
|
||
typedef X type;
|
||
};
|
||
</pre>
|
||
</p><p>
|
||
The specializations can define arbitrary mappings from the argument types
|
||
to the return type.
|
||
|
||
Suppose we have some mathematical vector type, templated on the element type:
|
||
|
||
<pre class="programlisting">
|
||
template <class T> class my_vector;
|
||
</pre>
|
||
|
||
Suppose the addition operator is defined between any two
|
||
<tt>my_vector</tt> instantiations,
|
||
as long as the addition operator is defined between their element types.
|
||
|
||
Furthermore, the element type of the resulting <tt>my_vector</tt>
|
||
is the same as the result type of the addition between the element types.
|
||
|
||
E.g., adding <tt>my_vector<int></tt> and
|
||
<tt>my_vector<double></tt> results in
|
||
<tt>my_vector<double></tt>.
|
||
|
||
The BLL has traits classes to perform the implicit built-in and standard
|
||
type conversions between integral, floating point, and complex classes.
|
||
|
||
Using BLL tools, the addition operator described above can be defined as:
|
||
|
||
<pre class="programlisting">
|
||
template<class A, class B>
|
||
my_vector<typename return_type_2<arithmetic_action<plus_action>, A, B>::type>
|
||
operator+(const my_vector<A>& a, const my_vector<B>& b)
|
||
{
|
||
typedef typename
|
||
return_type_2<arithmetic_action<plus_action>, A, B>::type res_type;
|
||
return my_vector<res_type>();
|
||
}
|
||
</pre>
|
||
</p><p>
|
||
To allow BLL to deduce the type of <tt>my_vector</tt>
|
||
additions correctly, we can define:
|
||
|
||
<pre class="programlisting">
|
||
template<class A, class B>
|
||
class plain_return_type_2<arithmetic_action<plus_action>,
|
||
my_vector<A>, my_vector<B> > {
|
||
typedef typename
|
||
return_type_2<arithmetic_action<plus_action>, A, B>::type res_type;
|
||
public:
|
||
typedef my_vector<res_type> type;
|
||
};
|
||
</pre>
|
||
Note, that we are reusing the existing specializations for the
|
||
BLL <tt>return_type_2</tt> template,
|
||
which require that the argument types are references.
|
||
</p><div class="table"><p><a name="table:actions"></a><b>Table 2. Action types</b></p><table summary="Action types" border="1"><colgroup><col><col></colgroup><tbody><tr><td><tt>+</tt></td><td><tt>arithmetic_action<plus_action></tt></td></tr><tr><td><tt>-</tt></td><td><tt>arithmetic_action<minus_action></tt></td></tr><tr><td><tt>*</tt></td><td><tt>arithmetic_action<multiply_action></tt></td></tr><tr><td><tt>/</tt></td><td><tt>arithmetic_action<divide_action></tt></td></tr><tr><td><tt>%</tt></td><td><tt>arithmetic_action<remainder_action></tt></td></tr><tr><td><tt>+</tt></td><td><tt>unary_arithmetic_action<plus_action></tt></td></tr><tr><td><tt>-</tt></td><td><tt>unary_arithmetic_action<minus_action></tt></td></tr><tr><td><tt>&</tt></td><td><tt>bitwise_action<and_action></tt></td></tr><tr><td><tt>|</tt></td><td><tt>bitwise_action<or_action></tt></td></tr><tr><td><tt>~</tt></td><td><tt>bitwise_action<not_action></tt></td></tr><tr><td><tt>^</tt></td><td><tt>bitwise_action<xor_action></tt></td></tr><tr><td><tt><<</tt></td><td><tt>bitwise_action<leftshift_action_no_stream></tt></td></tr><tr><td><tt>>></tt></td><td><tt>bitwise_action<rightshift_action_no_stream></tt></td></tr><tr><td><tt>&&</tt></td><td><tt>logical_action<and_action></tt></td></tr><tr><td><tt>||</tt></td><td><tt>logical_action<or_action></tt></td></tr><tr><td><tt>!</tt></td><td><tt>logical_action<not_action></tt></td></tr><tr><td><tt><</tt></td><td><tt>relational_action<less_action></tt></td></tr><tr><td><tt>></tt></td><td><tt>relational_action<greater_action></tt></td></tr><tr><td><tt><=</tt></td><td><tt>relational_action<lessorequal_action></tt></td></tr><tr><td><tt>>=</tt></td><td><tt>relational_action<greaterorequal_action></tt></td></tr><tr><td><tt>==</tt></td><td><tt>relational_action<equal_action></tt></td></tr><tr><td><tt>!=</tt></td><td><tt>relational_action<notequal_action></tt></td></tr><tr><td><tt>+=</tt></td><td><tt>arithmetic_assignment_action<plus_action></tt></td></tr><tr><td><tt>-=</tt></td><td><tt>arithmetic_assignment_action<minus_action></tt></td></tr><tr><td><tt>*=</tt></td><td><tt>arithmetic_assignment_action<multiply_action></tt></td></tr><tr><td><tt>/=</tt></td><td><tt>arithmetic_assignment_action<divide_action></tt></td></tr><tr><td><tt>%=</tt></td><td><tt>arithmetic_assignment_action<remainder_action></tt></td></tr><tr><td><tt>&=</tt></td><td><tt>bitwise_assignment_action<and_action></tt></td></tr><tr><td><tt>=|</tt></td><td><tt>bitwise_assignment_action<or_action></tt></td></tr><tr><td><tt>^=</tt></td><td><tt>bitwise_assignment_action<xor_action></tt></td></tr><tr><td><tt><<=</tt></td><td><tt>bitwise_assignment_action<leftshift_action></tt></td></tr><tr><td><tt>>>=</tt></td><td><tt>bitwise_assignment_action<rightshift_action></tt></td></tr><tr><td><tt>++</tt></td><td><tt>pre_increment_decrement_action<increment_action></tt></td></tr><tr><td><tt>--</tt></td><td><tt>pre_increment_decrement_action<decrement_action></tt></td></tr><tr><td><tt>++</tt></td><td><tt>post_increment_decrement_action<increment_action></tt></td></tr><tr><td><tt>--</tt></td><td><tt>post_increment_decrement_action<decrement_action></tt></td></tr><tr><td><tt>&</tt></td><td><tt>other_action<address_of_action></tt></td></tr><tr><td><tt>*</tt></td><td><tt>other_action<contents_of_action></tt></td></tr><tr><td><tt>,</tt></td><td><tt>other_action<comma_action></tt></td></tr></tbody></table></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ar01s05.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ar01s07.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">5. Lambda expressions in details </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 7. Practical considerations</td></tr></table></div></body></html>
|