<?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>Soul Of Free Loop &#187; boost</title>
	<atom:link href="https://zohead.com/archives/category/technology/boost/feed" rel="self" type="application/rss+xml" />
	<link>https://zohead.com</link>
	<description>Uranus Zhou&#039;s Blog</description>
	<lastBuildDate>Sat, 19 Jul 2025 15:42:46 +0000</lastBuildDate>
	<language>zh-CN</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.8</generator>
	<item>
		<title>bind2nd普通二元函数时无法使用引用类型参数的问题</title>
		<link>https://zohead.com/archives/cplusplus-bind2nd-reference/</link>
		<comments>https://zohead.com/archives/cplusplus-bind2nd-reference/#comments</comments>
		<pubDate>Wed, 09 May 2012 17:32:03 +0000</pubDate>
		<dc:creator><![CDATA[Uranus Zhou]]></dc:creator>
				<category><![CDATA[boost]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[技术]]></category>
		<category><![CDATA[bind2nd]]></category>
		<category><![CDATA[find_if]]></category>
		<category><![CDATA[ptr_fun]]></category>
		<category><![CDATA[STL]]></category>
		<category><![CDATA[引用]]></category>
		<category><![CDATA[编程]]></category>

		<guid isPermaLink="false">http://zohead.com/?p=115</guid>
		<description><![CDATA[本文同步自（如浏览不正常请点击跳转）：https://zohead.com/archives/cplusplus-bind2nd-reference/ 在使用 STL 的 find_if、count_if 等函数时会发现这些函数使用的参数不是普通的函数指针，而是 functional 函数对象，实际使用函数对象时可以自己定义一个仿函数来实现（实现带参数的 operator () 即可），这个相对比较简单就不写出来了。但有些情况需要直接使用普通的二元函数指针，这时可以使用 ptr_fun 将函数指针转换为函数对象作为 find_if、count_if 等的参数。 先看一个能正常工作的二元函数不使 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>本文同步自（如浏览不正常请点击跳转）：<a href="https://zohead.com/archives/cplusplus-bind2nd-reference/" target="_blank">https://zohead.com/archives/cplusplus-bind2nd-reference/</a></p>
<p>在使用 STL 的 find_if、count_if 等函数时会发现这些函数使用的参数不是普通的函数指针，而是 functional 函数对象，实际使用函数对象时可以自己定义一个仿函数来实现（实现带参数的 operator () 即可），这个相对比较简单就不写出来了。但有些情况需要直接使用普通的二元函数指针，这时可以使用 ptr_fun 将函数指针转换为函数对象作为 find_if、count_if 等的参数。</p>
<p>先看一个能正常工作的二元函数不使用引用类型参数的代码：</p>
<pre class="brush: cpp; highlight: [15,24,27,43]; title: cat &gt; test.cpp; notranslate">
#include &lt;iostream&gt;
#include &lt;vector&gt;
#include &lt;algorithm&gt;
#include &lt;functional&gt;

using namespace std;

class sss
{
public:
	explicit sss(int val) : value(val) {}

	sss(const sss&amp; org)
	{
		cout &lt;&lt; &quot;---copy &quot; &lt;&lt; &amp;org &lt;&lt; &quot; to &quot; &lt;&lt; this &lt;&lt; endl;
		value = org.value;
	}

	virtual ~sss() {}

	int value;
};

bool find_sss(sss s_chk, int val)
{
	bool ret = (s_chk.value == val);
	s_chk.value = 222;
	return ret;
}

int main(int argc, char ** argv)
{
	vector&lt;sss&gt; vvv;
	vector&lt;sss&gt;::iterator iii;

	vvv.push_back(sss(11));
	vvv.push_back(sss(12));
	vvv.push_back(sss(13));
	vvv.push_back(sss(14));
	vvv.push_back(sss(15));

	cout &lt;&lt; &quot;before find_if&quot; &lt;&lt; endl;
	iii = find_if(vvv.begin(), vvv.end(), bind2nd(ptr_fun(find_sss), 13));

	if (iii == vvv.end())
		cout &lt;&lt; &quot;not found&quot; &lt;&lt; endl;
	else
		cout &lt;&lt; &quot;index: &quot; &lt;&lt; (iii - vvv.begin()) &lt;&lt; &quot;, value: &quot; &lt;&lt; iii-&gt;value &lt;&lt; endl;

	return 0;
}
</pre>
<p>程序很简单，从 vector 中查找符合条件的 sss 对象，find_sss 就是要转换的二元函数指针，第一个参数是 sss 类，通过 ptr_fun 可以使本代码正常工作。</p>
<p>通过下面的运行输出能看出调用 find_sss 时进行了拷贝构造（本程序的编译环境为：Windows 7 32bit, Mingw gcc 3.4.5，Visual Studio 2010中稍有不同，主要在前面的拷贝次数上）：<br />
<strong><span style="color: #800000;"><br />
---copy 0x22ff10 to 0x552a58<br />
---copy 0x552a58 to 0x552ad8<br />
---copy 0x22ff10 to 0x552ae0<br />
---copy 0x552ad8 to 0x552af0<br />
---copy 0x552ae0 to 0x552af8<br />
---copy 0x22ff10 to 0x552b00<br />
---copy 0x22ff10 to 0x552b08<br />
---copy 0x552af0 to 0x552b18<br />
---copy 0x552af8 to 0x552b20<br />
---copy 0x552b00 to 0x552b28<br />
---copy 0x552b08 to 0x552b30<br />
---copy 0x22ff10 to 0x552b38<br />
before find_if<br />
---copy 0x552b18 to 0x22fdd0<br />
---copy 0x22fdd0 to 0x22fd40<br />
---copy 0x552b20 to 0x22fdd0<br />
---copy 0x22fdd0 to 0x22fd40<br />
---copy 0x552b28 to 0x22fdd0<br />
---copy 0x22fdd0 to 0x22fd40<br />
index: 2, value: 13<br />
</span></strong></p>
<p>接下来就是实际碰到的问题了，如果将 find_sss 的第一个参数改为 sss 的引用，即第 24 行改为：</p>
<p><span style="color: #006400;"><em><strong><span style="color: #008000;">bool find_sss(sss&amp; s_chk, int val)</span><br />
</strong></em></span></p>
<p>上面的代码就会编译出错（以 Visual Studio 2010 的错误输出为例）：</p>
<hr size="1" />
<p><span style="color: #0000ff;">C:\Program Files\Microsoft Visual Studio 10.0\VC\INCLUDE\xfunctional(341) : error C2535: “bool std::binder2nd&lt;_Fn2&gt;::operator ()(sss &amp;) const”: 已经定义或声明成员函数<br />
with<br />
[<br />
_Fn2=std::pointer_to_binary_function&lt;sss &amp;,int,bool,bool (__cdecl *)(sss &amp;,int)&gt;<br />
]<br />
C:\Program Files\Microsoft Visual Studio 10.0\VC\INCLUDE\xfunctional(335) : 参见“std::binder2nd&lt;_Fn2&gt;::operator ()”的声明<br />
with<br />
[<br />
_Fn2=std::pointer_to_binary_function&lt;sss &amp;,int,bool,bool (__cdecl *)(sss &amp;,int)&gt;<br />
]<br />
test.cpp(43): 参见对正在编译的类 模板 实例化“std::binder2nd&lt;_Fn2&gt;”的引用<br />
with<br />
[<br />
_Fn2=std::pointer_to_binary_function&lt;sss &amp;,int,bool,bool (__cdecl *)(sss &amp;,int)&gt;<br />
]<br />
</span></p>
<hr size="1" />
<p>网上的码农和攻城师们基本都认为是 STL 本身的问题，传递引用类型参数会造成 reference to reference 问题。</p>
<p>几番尝试之后，发现的解决方法如下：</p>
<p><strong>1、Visual Studio 2010下的不完美解决方法：</strong></p>
<p>将第 43 行改为：</p>
<p><strong><span style="color: #006400;">    iii = find_if(vvv.begin(), vvv.end(), bind2nd(pointer_to_binary_function&lt;sss, int, bool, bool(*)(sss&amp;, int)&gt;(find_sss), 13));<br />
</span></strong></p>
<p>这样通过自己给 pointer_to_binary_function 设置模板参数避免编译出错，实际运行中会发现 find_if 查找可以正常工作了，但第 27 行中修改引用类的值会没有效果，因为这种方式不是真正的引用，仍然有拷贝构造，由于需要用到这些二元函数的场合一般不需要修改数据，使用起来没有太大问题。</p>
<p><strong>2、gcc下的不完美解决方法：</strong></p>
<p>如果 gcc 下用上面的改动，你会发现由于 gcc 下 pointer_to_binary_function 只有 3 个参数，无法顺利修改编译，但可以这样折中，将第 43 行改为：</p>
<p><strong><span style="color: #006400;">    iii = find_if(vvv.begin(), vvv.end(), bind2nd(ptr_fun((bool(*)(sss, int)) find_sss), 13));<br />
</span></strong></p>
<p>通过强制类型转换来实现，稍显恶心，查找可以正常工作，但依然是拷贝构造。需要注意此方法如果在 Visual Studio 中使用会出错。</p>
<p><strong>3、终极解决方案- 使用 boost 库：</strong></p>
<p>首先头文件中增加：</p>
<p><strong><span style="color: #006400;">#include &lt;boost/functional.hpp&gt;</span></strong></p>
<p>然后原来的第 43 行改为：</p>
<p><strong><span style="color: #006400;">    iii = find_if(vvv.begin(), vvv.end(), boost::bind2nd(boost::ptr_fun(find_sss), 13));<br />
</span></strong></p>
<p>编译运行之后发现 find_if 查找可以正常工作，而且现在是真正的引用，只能说 boost 的 functional 相比 STL 的实在是好强大，哈哈。</p>
<p>运行输出如下（使用 Mingw gcc 3.4.5 编译），find_if 找到的值已经被 find_sss 修改：</p>
<p><strong><span style="color: #800000;">---copy 0x22ff10 to 0x7f2a58<br />
---copy 0x7f2a58 to 0x7f2ad8<br />
---copy 0x22ff10 to 0x7f2ae0<br />
---copy 0x7f2ad8 to 0x7f2af0<br />
---copy 0x7f2ae0 to 0x7f2af8<br />
---copy 0x22ff10 to 0x7f2b00<br />
---copy 0x22ff10 to 0x7f2b08<br />
---copy 0x7f2af0 to 0x7f2b18<br />
---copy 0x7f2af8 to 0x7f2b20<br />
---copy 0x7f2b00 to 0x7f2b28<br />
---copy 0x7f2b08 to 0x7f2b30<br />
---copy 0x22ff10 to 0x7f2b38<br />
before find_if<br />
<span style="color: #f00;">index: 2, value: 222</span><br />
</span></strong></p>
<p>以上仅为个人小心得，有任何问题欢迎指正，玩的开心咯 ^_^</p>
]]></content:encoded>
			<wfw:commentRss>https://zohead.com/archives/cplusplus-bind2nd-reference/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
