<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>X the Unknown &#187; 高阶函数</title>
	<atom:link href="http://www.xinside.net/tag/high-order-functions/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.xinside.net</link>
	<description>Becoming an ``X&#039;&#039; in an equation.</description>
	<lastBuildDate>Tue, 06 Sep 2011 02:51:50 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=</generator>
		<item>
		<title>C++高阶函数（一）</title>
		<link>http://www.xinside.net/2009/02/23/cpp-high-order-functions-1/</link>
		<comments>http://www.xinside.net/2009/02/23/cpp-high-order-functions-1/#comments</comments>
		<pubDate>Mon, 23 Feb 2009 06:46:56 +0000</pubDate>
		<dc:creator>X</dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[程序设计]]></category>
		<category><![CDATA[高阶函数]]></category>

		<guid isPermaLink="false">http://www.xinside.net/?p=405</guid>
		<description><![CDATA[这是C++高阶函数学习的第一篇，主要分析std::bind1st/std::bind2nd的使用和实现原理。]]></description>
			<content:encoded><![CDATA[<p><strong>0. 前言</strong></p>
<p>看见了标题不要以为以下的内容是C++的高级话题。这里的``高阶''是与``函数''连在一起作为名词的。高阶函数（high-order functions）有点借用了数学中高阶的概念。当一个函数是以另一个函数作为参数，或者以另一个函数作为返回值的时候（或者两者兼备），就可以称作是高阶函数。举个例说：</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">typedef</span> <span style="color: #0000ff;">int</span> <span style="color: #008000;">&#40;</span><span style="color: #000040;">*</span>int_func<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
&nbsp;
<span style="color: #0000ff;">int</span> f<span style="color: #008000;">&#40;</span>int_func g, <span style="color: #0000ff;">int</span> x<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
   <span style="color: #0000ff;">return</span> g<span style="color: #008000;">&#40;</span>x<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></div></div>

<p>这里，函数 f 就可以称作是一个高阶函数，因为它以另一个函数（实参 g ）为参数。</p>
<p>高阶函数在函数式编程里面是很普遍，在命令式编程里面可能比较少提到，但对于C++来说，高阶函数已经不是新事物了。很多地方，例如C++的标准库自身，或者C++的巨牛库boost，对在C++中使用高阶函数已经有不同方面的支持。虽然目前还有很多方面我还没有触及到，但为了避免自己没记性忘掉，我还是准备把我不完全的认识先记录下来，日后继续慢慢更新。嗯，期待自己能写出一个系列呢~。</p>
<p><strong>1. 函数的生成</strong></p>
<p><strong>生成函数？</strong></p>
<p>假如现在有一个简单的函数（实际上是函数对象。这里用的是函数的纯抽象概念：只要表现得和函数一样的，都可以叫作``函''。下面的描述，如果不需要严格区分函数和函数对象，那么我一律称作函数），作用是做加法的：</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">template</span> <span style="color: #000080;">&lt;</span><span style="color: #0000ff;">class</span> T<span style="color: #000080;">&gt;</span>
<span style="color: #0000ff;">struct</span> x_plus <span style="color: #008000;">&#123;</span>
   T operator <span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#40;</span>T op1, T op2<span style="color: #008000;">&#41;</span> <span style="color: #0000ff;">const</span> <span style="color: #008000;">&#123;</span>
      <span style="color: #0000ff;">return</span> op1<span style="color: #000040;">+</span>op2<span style="color: #008080;">;</span>
   <span style="color: #008000;">&#125;</span>
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span></pre></div></div>

<p>如果有两个int变量x, y，那么</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;">x_plus<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #000080;">&gt;</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#40;</span>x, y<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></pre></div></div>

<p>得到的结果就是x+y。对于x_plus&lt;int&gt;()来说，它是一个二元函数。</p>
<p>通过把其中一个值变成常量，x_plus&lt;int&gt;()就可以表现像一个一元函数了：</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;">x_plus<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #000080;">&gt;</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#40;</span>x, <span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #666666;">//     ---------------     (1)</span></pre></div></div>

<p>相当于计算x+1。</p>
<p>函数生成的过程与上面的这个过程是类似的。通过将一个函数的某一个变量绑定为另外一个变量，就可以得到一个新的函数。</p>
<p>然而严格地说，上面的函数调用(1)依旧是二元函数，只不过其中一个参数被固定了。对于一个一元函数，它被期望的调用方式应该是：</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;">_i_am_an_unary_function_<span style="color: #008000;">&#40;</span>x<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></pre></div></div>

<p>于是，在对于一些需要使用一元函数的场合，x_plus&lt;int&gt;()是无法使用的：</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">template</span> <span style="color: #000080;">&lt;</span><span style="color: #0000ff;">class</span> unary_function<span style="color: #000080;">&gt;</span>
<span style="color: #0000ff;">inline</span> <span style="color: #0000ff;">int</span> _i_need_an_unary_func <span style="color: #008000;">&#40;</span>unary_function f, <span style="color: #0000ff;">int</span> x<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
   <span style="color: #0000ff;">return</span> unary_function<span style="color: #008000;">&#40;</span>x<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span>
&nbsp;
_i_need_an_unary_func <span style="color: #008000;">&#40;</span> x_plus<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #000080;">&gt;</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#40;</span>x, <span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span>, <span style="color: #0000dd;">10</span> <span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #666666;">// error</span></pre></div></div>

<p><strong>std::bind1st和std::bind2nd</strong></p>
<p>标准库的std::bind1st和std::bind2nd提供了一个解决方案，使得我们可以将x_plus&lt;int&gt;()转化为一个真正的一元函数：</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #339900;">#include&lt;functional&gt;</span>
<span style="color: #0000ff;">using</span> <span style="color: #0000ff;">namespace</span> std<span style="color: #008080;">;</span>
&nbsp;
_i_need_an_unary_func <span style="color: #008000;">&#40;</span> bind2nd<span style="color: #008000;">&#40;</span>x_plus<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #000080;">&gt;</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, <span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span>, <span style="color: #0000dd;">10</span> <span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #666666;">// ok</span>
_i_need_an_unary_func <span style="color: #008000;">&#40;</span> bind2nd<span style="color: #008000;">&#40;</span>x_plus<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #000080;">&gt;</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, <span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span>, <span style="color: #0000dd;">10</span> <span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #666666;">// ok</span></pre></div></div>

<p>这里的x_plus&lt;&gt;实现于最开始时候定义的有点区别，会在后面说明。</p>
<p>std::bind2nd(x_plus&lt;int&gt;(), 1)和x_plus&lt;int&gt;()(x, 1)的区别在于前者将一个参数绑定到某个已有函数的某个实参上，从而生成一个新的函数，而后者是一个函数调用（而且是不合法的函数调用，这里的 x 会因为未定义而产生编译错误）。所以对于std::bind2nd(x_plus&lt;int&gt;(), 1)，以下的调用是合法的：</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;">bind2nd<span style="color: #008000;">&#40;</span>x_plus<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #000080;">&gt;</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, <span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">10</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #666666;">// ok, equivalent to function call: x_plus&lt;int&gt;()(10, 1)</span></pre></div></div>

<p>std::bind1st和std::bind2nd是类似的，区别在于绑定参数的位置不一样：</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;">bind1st<span style="color: #008000;">&#40;</span>x_plus<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #000080;">&gt;</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, <span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">10</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #666666;">// =&gt; x_plus&lt;int&gt;()(1, 10)</span>
bind2nd<span style="color: #008000;">&#40;</span>x_plus<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #000080;">&gt;</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, <span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">10</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #666666;">// =&gt; x_plus&lt;int&gt;()(10, 1)</span></pre></div></div>

<p>因为std::bind1st和std::bind2nd的实现是类似的，我只考虑实现其中一个的基本原理：</p>
<p>bind1st返回的可以是普通函数指针或者函数对象，然而对于返回普通函数指针，实现起来似乎不怎么方便&gt;<a name="context1" href="#comment1">*</a>&lt;，所以一般都是返回函数对象：</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">template</span> <span style="color: #000080;">&lt;</span><span style="color: #0000ff;">class</span> F, <span style="color: #0000ff;">class</span> A1<span style="color: #000080;">&gt;</span>
<span style="color: #0000ff;">struct</span> x_bind1st_c <span style="color: #008000;">&#123;</span>
   x_bind1st_c<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> F<span style="color: #000040;">&amp;</span> _f, A1 _a1<span style="color: #008000;">&#41;</span> <span style="color: #008080;">:</span> f<span style="color: #008000;">&#40;</span>_f<span style="color: #008000;">&#41;</span>, a1<span style="color: #008000;">&#40;</span>_a1<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <span style="color: #008000;">&#125;</span>
&nbsp;
   return_type<span style="color: #008080;">?</span> operator <span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#40;</span>argument_type<span style="color: #008080;">?</span> a2<span style="color: #008000;">&#41;</span> <span style="color: #0000ff;">const</span> <span style="color: #008000;">&#123;</span>
      <span style="color: #0000ff;">return</span> f<span style="color: #008000;">&#40;</span>a1, a2<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
   <span style="color: #008000;">&#125;</span>
<span style="color: #0000ff;">private</span><span style="color: #008080;">:</span>
   F f<span style="color: #008080;">;</span>
   A1 a1<span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span></pre></div></div>

<p>上面的实现还未完整，但不妨先进行分析。通过x_bind1st_c&lt; x_plus&lt;int&gt;, int &gt;(x_plus&lt;int&gt;(), 1)，就可以产生一个函数对象func。函数对象里面已经定义了operator()(...)的成员，所以可以通过func(x)的方式来调用这个函数对象，达到预期的效果。</p>
<p>实现中还有部分地方没有明确：operator()(...)的返回类型是什么？实参a2的类型又是什么？或许可以假定为与A1相同，但这毕竟没有普适性：要求一个函数的返回值与实参类型相同、所有实参的类型都一样，这样的要求显然不合理。函数需要返回什么值，实参接受什么类型，是被绑定的函数决定的，如此考虑的话，直接从被绑定函数中获取是最好的方法。为了这样，需要对x_plus&lt;&gt;的定义稍微修改一下：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>21
22
23
24
25
26
27
28
29
30
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">template</span> <span style="color: #000080;">&lt;</span><span style="color: #0000ff;">class</span> T<span style="color: #000080;">&gt;</span>
<span style="color: #0000ff;">struct</span> x_plus <span style="color: #008000;">&#123;</span>
   <span style="color: #0000ff;">typedef</span> T return_type<span style="color: #008080;">;</span>
   <span style="color: #0000ff;">typedef</span> T arg1_type<span style="color: #008080;">;</span>
   <span style="color: #0000ff;">typedef</span> T arg2_type<span style="color: #008080;">;</span>
&nbsp;
   T operator <span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#40;</span>T op1, T op2<span style="color: #008000;">&#41;</span> <span style="color: #0000ff;">const</span> <span style="color: #008000;">&#123;</span>
      <span style="color: #0000ff;">return</span> op1<span style="color: #000040;">+</span>op2<span style="color: #008080;">;</span>
   <span style="color: #008000;">&#125;</span>
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span></pre></td></tr></table></div>

<p>然后……重新写一次完整的x_bind1st_c的定义吧：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">template</span> <span style="color: #000080;">&lt;</span><span style="color: #0000ff;">class</span> F<span style="color: #000080;">&gt;</span>
<span style="color: #0000ff;">struct</span> x_bind1st_c <span style="color: #008000;">&#123;</span>
   <span style="color: #0000ff;">typedef</span> <span style="color: #0000ff;">typename</span> F<span style="color: #008080;">::</span><span style="color: #007788;">return_type</span> return_type<span style="color: #008080;">;</span>
   <span style="color: #0000ff;">typedef</span> <span style="color: #0000ff;">typename</span> F<span style="color: #008080;">::</span><span style="color: #007788;">arg1_type</span> arg1_type<span style="color: #008080;">;</span>
   <span style="color: #0000ff;">typedef</span> <span style="color: #0000ff;">typename</span> F<span style="color: #008080;">::</span><span style="color: #007788;">arg2_type</span> arg2_type<span style="color: #008080;">;</span>
&nbsp;
   x_bind1st_c<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> F<span style="color: #000040;">&amp;</span> _f, arg1_type _a1<span style="color: #008000;">&#41;</span> <span style="color: #008080;">:</span> f<span style="color: #008000;">&#40;</span>_f<span style="color: #008000;">&#41;</span>, a1<span style="color: #008000;">&#40;</span>_a1<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <span style="color: #008000;">&#125;</span>
&nbsp;
   return_type operator <span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#40;</span>arg2_type a2<span style="color: #008000;">&#41;</span> <span style="color: #0000ff;">const</span> <span style="color: #008000;">&#123;</span>
      <span style="color: #0000ff;">return</span> f<span style="color: #008000;">&#40;</span>a1, a2<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
   <span style="color: #008000;">&#125;</span>
<span style="color: #0000ff;">private</span><span style="color: #008080;">:</span>
   F f<span style="color: #008080;">;</span>
   arg1_type a1<span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span></pre></td></tr></table></div>

<p>x_bind1st_c是一个类模板，使用的时候必须显式指定模板的参数。可以利用函数模板的自动推导简化使用：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>16
17
18
19
20
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">template</span> <span style="color: #000080;">&lt;</span><span style="color: #0000ff;">class</span> F<span style="color: #000080;">&gt;</span>
<span style="color: #0000ff;">inline</span> x_bind1st_c<span style="color: #000080;">&lt;</span>F<span style="color: #000080;">&gt;</span>
x_bind1st<span style="color: #008000;">&#40;</span>F f, <span style="color: #0000ff;">typename</span> F<span style="color: #008080;">::</span><span style="color: #007788;">arg1_type</span> a1<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
   <span style="color: #0000ff;">return</span> x_bind1st_c<span style="color: #000080;">&lt;</span>F<span style="color: #000080;">&gt;</span><span style="color: #008000;">&#40;</span>f, a1<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>x_bind1st就这样完成了。（我并没有看过标准库的实现，所以我不保证这就是std::bind1st的实现方式。事实上我觉得标准库应该比我上面简单的实现考虑得更多，比如const和volatile关键字的修饰。不过我觉得基本原理应该是这样的。）</p>
<p>x_bind1st（算是简化+删节版的std::bind1st吧，所以下面把两者合在一起统称bind1st/bind2nd）的实现同时也提示了几点：</p>
<p>1、只能用在接受两个参数的函数对象上。</p>
<p>所以对于非二元的函数对象，无法使用bind1st/bind2nd；而且对于普通的函数，因为缺少return_type、arg1_type和arg2_type的定义，所以也不能直接使用；相同的情况存在于类成员函数指针中，不过成员函数指针的情况有点特殊，下面将会提及。</p>
<p>为了让bind1st/bind2nd可以为普通的函数绑定，标准库定义了一个ptr_fun，用来包装普通函数，使得bind1st/bind2nd可以用在普通函数上；对于类成员函数指针，标准库也定义了mem_fun/mem_fun_ref来包装，使得bind1st/bind2nd可以用在成员函数指针上：</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">int</span> func1<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> op1, <span style="color: #0000ff;">int</span> op2<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
   <span style="color: #0000ff;">return</span> op1<span style="color: #000040;">+</span>op2<span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span>
&nbsp;
<span style="color: #0000ff;">struct</span> X <span style="color: #008000;">&#123;</span>
   <span style="color: #0000ff;">int</span> func2<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> op<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
      <span style="color: #0000ff;">return</span> op<span style="color: #008080;">;</span>
   <span style="color: #008000;">&#125;</span>
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>
&nbsp;
std<span style="color: #008080;">::</span><span style="color: #007788;">bind2nd</span><span style="color: #008000;">&#40;</span>std<span style="color: #008080;">::</span><span style="color: #007788;">ptr_fuc</span><span style="color: #008000;">&#40;</span>func1<span style="color: #008000;">&#41;</span>, <span style="color: #0000dd;">10</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">20</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
std<span style="color: #008080;">::</span><span style="color: #007788;">bind1st</span><span style="color: #008000;">&#40;</span>std<span style="color: #008080;">::</span><span style="color: #007788;">mem_fun</span><span style="color: #008000;">&#40;</span><span style="color: #000040;">&amp;</span>X<span style="color: #008080;">::</span><span style="color: #007788;">func2</span><span style="color: #008000;">&#41;</span>, <span style="color: #000040;">&amp;</span>x<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">10</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></pre></div></div>

<p>成员函数X::func2只接受一个参数似乎和之前的说明矛盾。其实这是因为成员函数需要接受一个额外的参数（this指针的由来）。除去这个额外参数以后，就只能再接收一个了。</p>
<p>2、被绑定的参数只能是兼容于被绑定函数的可接收参数的类型（即存在隐式转换）。</p>
<p>简单的说就是你不能这样调用bind1st/bind2nd来实现生成类似于f(x)=(10+x)+x的函数：</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;">std<span style="color: #008080;">::</span><span style="color: #007788;">bind1st</span><span style="color: #008000;">&#40;</span>
   x_plus<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #000080;">&gt;</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>,
   std<span style="color: #008080;">::</span><span style="color: #007788;">bind1st</span><span style="color: #008000;">&#40;</span>x_plus<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #000080;">&gt;</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, <span style="color: #0000dd;">10</span><span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">20</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></pre></div></div>

<p>原因很简单，因为经过bind1st/bind2nd后得到的是一个函数。除非原来的函数接受的就是函数类型的参数，否则，由于不存在隐式转换，这样的调用将产生错误。</p>
<hr />
<p><a name="comment1">*</a> 或许可以考虑一下返回的是一个函数指针。但如果返回的是一个函数指针，那么这个函数的定义至少应该类似于：</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;">R bind1st<span style="color: #008000;">&#40;</span>A2 a2<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
   <span style="color: #0000ff;">return</span> <span style="color: #000040;">&amp;</span>func_to_be_bound<span style="color: #008000;">&#40;</span>a1_bound, a2<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></div></div>

<p>返回值、参数a1和a2的类型先不作考虑。</p>
<p>为了记录func_to_be_bound，bind1st必须定义为一个函数模板。这样的话就要求函数的参数列表中须新增用来接受func_to_be_bound的形参。这样的话又会破环bind1st的接口：</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">template</span> <span style="color: #000080;">&lt;</span><span style="color: #0000ff;">class</span> f<span style="color: #000080;">&gt;</span>
R bind1st<span style="color: #008000;">&#40;</span>A2 a2, f func_to_be_bound<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></pre></div></div>

<p>另一个可能的形式是这样：</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">template</span> <span style="color: #000080;">&lt;</span><span style="color: #0000ff;">class</span> F, F f<span style="color: #000080;">&gt;</span>
R bind1st<span style="color: #008000;">&#40;</span>A2 a2<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
   retrun f<span style="color: #008000;">&#40;</span>a1, a2<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></div></div>

<p>这种形式中 f 是一个非类型的模板参数。如果 F 是一个指针类型的话， f 就是一个指针，也能算是整型的非模板参数，所以这样的形式是接受的。问题在于调用须以这样的形式进行：</p>
<pre>bind1st<F_type, f_ptr>(a2_arg);</pre>
<p>和之前的bind1st的用法差别甚大。或许可以尝试写一个辅助函数来简化：</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">template</span> <span style="color: #000080;">&lt;</span><span style="color: #0000ff;">class</span> F<span style="color: #000080;">&gt;</span>
R bind1st_aux<span style="color: #008000;">&#40;</span>F f<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
   <span style="color: #0000ff;">return</span> <span style="color: #000040;">&amp;</span><span style="color: #008000;">&#40;</span>bind1st<span style="color: #000080;">&lt;</span>F, f<span style="color: #000080;">&gt;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></div></div>

<p>然而这种方式实际使用中会产生编译错误，因为模板的实例化参数使用了函数参数。函数参数的值是在运行期才能决定的，而模板则要求在编译期完成实例化。</p>
<p>而且上面那样的函数模板无法接受非整型的函数对象作为模板参数，除非把函数对象定义为全局变量，并将函数对象的地址作为参数传入。局部变量因为储存在栈区，地址取决于栈的使用状况，故只能在运行期判明，不能用作模板参数（我认为理论上静态变量也是可以的，因为都是储存在静态区，地址是可以在编译期决定的。不过在gcc 3.4.5上只有使用全局对象时编译才能通过）。</p>
<p>暂时能想到的用普通函数指针来实现会存在的问题就这些，似乎对于普通函数指针来说限制是比较多的。如果哪位有用普通函数指针的不错的实现的话，请告诉我吧！</p>
<p>另外，这不知道算不算是函数对象比普通函数要灵活的一个例子呢？</p>
<p>&gt;<a href="#context1">back</a>&lt;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.xinside.net/2009/02/23/cpp-high-order-functions-1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

