<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">博客园_小李美刀</title><subtitle type="text">我不去想是否能够成功既然选择了远方便只顾风雨兼程</subtitle><id>http://feed.cnblogs.com/blog/u/29370/rss</id><updated>2012-01-12T08:37:44Z</updated><author><name>Ady Lee</name><uri>http://www.cnblogs.com/adylee/</uri></author><generator>feed.cnblogs.com</generator><link rel="alternate" type="text/html" href="http://www.cnblogs.com/adylee/"/><link rel="self" type="application/atom+xml" href="http://feed.cnblogs.com/blog/u/29370/rss"/><entry><id>http://www.cnblogs.com/adylee/archive/2012/01/12/2320783.html</id><title type="text">[转]PFX证书导入到USBKEY(代码)</title><summary type="text">5. 完整代码 #include "stdafx.h"#include &lt;windows.h&gt;#include &lt;WinCrypt.h&gt;#include &lt;stdio.h&gt; // Global Csp HandleHCRYPTPROV hCryptProv = NULL; // Handle for a cryptographic void ToSmartCard(HCERTSTORE hSystemStore){PCCERT_CONTEXT pCertContext = NULL; char pszNameString[256]; DW</summary><published>2012-01-12T08:32:00Z</published><updated>2012-01-12T08:32:00Z</updated><author><name>Ady Lee</name><uri>http://www.cnblogs.com/adylee/</uri></author><link rel="alternate" href="http://www.cnblogs.com/adylee/archive/2012/01/12/2320783.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/adylee/archive/2012/01/12/2320783.html"/><content type="html">&lt;div&gt;&lt;p&gt;5. 完整代码&lt;/p&gt; &lt;p&gt;#include "stdafx.h"&lt;br /&gt;#include &amp;lt;windows.h&amp;gt;&lt;br /&gt;#include  &amp;lt;WinCrypt.h&amp;gt;&lt;br /&gt;#include &amp;lt;stdio.h&amp;gt;&lt;/p&gt; &lt;p&gt;// Global Csp Handle&lt;br /&gt;HCRYPTPROV hCryptProv = NULL;        // Handle for a  cryptographic&lt;/p&gt; &lt;p&gt;void ToSmartCard(HCERTSTORE hSystemStore)&lt;br /&gt;{&lt;br /&gt;PCCERT_CONTEXT pCertContext  = NULL; &lt;br /&gt;char            pszNameString[256]; &lt;br /&gt;DWORD            dwKeySpec;&lt;br /&gt;HCRYPTKEY       UserKey = 0;&lt;/p&gt; &lt;p&gt;DWORD dwBlobLen;&lt;br /&gt;BYTE *pbKeyBlob;&lt;br /&gt;HCRYPTKEY hPubKey = NULL;&lt;br /&gt;int  error;&lt;/p&gt; &lt;p&gt;// CryptAcquireCertificatePrivateKey Exported Handle&lt;br /&gt;HCRYPTPROV hCrypt =  NULL;&lt;/p&gt; &lt;p&gt;// Just for Test Provider Name&lt;br /&gt;BYTE       pbData[1000];       // 1000 will  hold the longest&lt;/p&gt; &lt;p&gt;// key container name.&lt;br /&gt;DWORD cbData;&lt;br /&gt;cbData = 1000;&lt;/p&gt; &lt;p&gt;//-------------------------------------------------------------------&lt;br /&gt;//  Find the certificates in the system store.&lt;br /&gt;// In fact, just have one.&lt;/p&gt; &lt;p&gt;while(pCertContext= CertEnumCertificatesInStore(&lt;br /&gt;   hSystemStore,&lt;br /&gt;    pCertContext)) // on the first call to the function,&lt;br /&gt;   // this parameter is  NULL &lt;br /&gt;   // on all subsequent calls, &lt;br /&gt;   // this parameter is the last  pointer &lt;br /&gt;   // returned by the function&lt;br /&gt;{&lt;br /&gt;    //----------------------------------------------------------------&lt;br /&gt;   // Do  whatever is needed for a current certificate.&lt;br /&gt;   // ...&lt;br /&gt;    //--------------------------------------------------------------------&lt;br /&gt;   //  Find and print the name of the subject of the certificate &lt;br /&gt;   // just  retrieved.&lt;/p&gt; &lt;p&gt;   if(CertGetNameString(   &lt;br /&gt;    pCertContext,   &lt;br /&gt;     CERT_NAME_SIMPLE_DISPLAY_TYPE,   &lt;br /&gt;    0,&lt;br /&gt;    NULL,   &lt;br /&gt;     pszNameString,   &lt;br /&gt;    128))&lt;br /&gt;   {&lt;br /&gt;    printf("Certificate for %s has  been retrieved.\n",pszNameString);&lt;/p&gt; &lt;p&gt;    if(!( CryptAcquireCertificatePrivateKey(&lt;br /&gt;     pCertContext,&lt;br /&gt;      0,&lt;br /&gt;     NULL,&lt;br /&gt;     &amp;amp;hCrypt, //&amp;amp;hCryptProv,     // 注意此处 hCrypt  输出不该是hCryptProv，如果没有猜错是Microsoft Base那个&lt;br /&gt;     &amp;amp;dwKeySpec,&lt;br /&gt;      NULL)))&lt;br /&gt;    {&lt;br /&gt;     printf("CryptAcquireCertificatePrivateKey.\n");&lt;br /&gt;     }&lt;/p&gt; &lt;p&gt;    // Test hCrypt, Try to get its name;&lt;br /&gt;    // 猜错了，不是Microsoft  Base...,而是下面这个&lt;br /&gt;    // Microsoft Enhanced Cryptographic Provider v1.0&lt;/p&gt; &lt;p&gt;    if(CryptGetProvParam(&lt;br /&gt;     hCrypt, &lt;br /&gt;     PP_NAME, &lt;br /&gt;     pbData,  &lt;br /&gt;     &amp;amp;cbData, &lt;br /&gt;     0))&lt;br /&gt;    {&lt;br /&gt;     printf("CryptGetProvParam  succeeded.\n");&lt;br /&gt;     printf("Provider name: %s\n", pbData);&lt;br /&gt;    }&lt;/p&gt; &lt;p&gt;    if( ! CryptGetUserKey(&lt;br /&gt;     hCrypt,    //not hCryptProv,&lt;br /&gt;      AT_KEYEXCHANGE, //dwKeySpec,&lt;br /&gt;     &amp;amp;UserKey&lt;br /&gt;     ) )&lt;/p&gt; &lt;p&gt;    {&lt;br /&gt;     printf("CryptGetUserKey Error.\n");&lt;br /&gt;    }&lt;/p&gt; &lt;p&gt;     //--------------------------------------------------------------------&lt;br /&gt;    //  Export the public/private key-pair.&lt;/p&gt; &lt;p&gt;    if(CryptExportKey(   &lt;br /&gt;     UserKey,    &lt;br /&gt;     NULL,    &lt;br /&gt;      PRIVATEKEYBLOB,&lt;br /&gt;     0,    &lt;br /&gt;     NULL, &lt;br /&gt;     &amp;amp;dwBlobLen)) &lt;br /&gt;     {&lt;br /&gt;     printf("Size of the BLOB for the public/private key pair determined.  \n");&lt;br /&gt;    }&lt;br /&gt;    else&lt;br /&gt;    {&lt;br /&gt;     printf("Error computing BLOB  length.\n");&lt;br /&gt;     exit(1);&lt;br /&gt;    }&lt;/p&gt; &lt;p&gt;     //--------------------------------------------------------------------&lt;br /&gt;    //  Allocate memory for the pbKeyBlob.&lt;/p&gt; &lt;p&gt;    if(pbKeyBlob = (BYTE*)malloc(dwBlobLen)) &lt;br /&gt;    {&lt;br /&gt;     printf("Memory  has been allocated for the BLOB. \n");&lt;br /&gt;    }&lt;br /&gt;    else&lt;br /&gt;    {&lt;br /&gt;      printf("Out of memory. \n");&lt;br /&gt;     exit(1);&lt;br /&gt;    }&lt;/p&gt; &lt;p&gt;     //--------------------------------------------------------------------&lt;br /&gt;    //  Do the actual exporting into the key BLOB.&lt;/p&gt; &lt;p&gt;    if(CryptExportKey(   &lt;br /&gt;     UserKey, &lt;br /&gt;     NULL,    &lt;br /&gt;      PRIVATEKEYBLOB,    &lt;br /&gt;     0,    &lt;br /&gt;     pbKeyBlob,    &lt;br /&gt;      &amp;amp;dwBlobLen))&lt;br /&gt;    {&lt;br /&gt;     printf("Contents have been written to the  BLOB. \n");&lt;br /&gt;    }&lt;br /&gt;    else&lt;br /&gt;    {&lt;br /&gt;     printf("Error exporting  key.\n");&lt;br /&gt;     exit(1);&lt;br /&gt;    }&lt;/p&gt; &lt;p&gt;    if(CryptImportKey(&lt;br /&gt;     hCryptProv,&lt;br /&gt;     pbKeyBlob,&lt;br /&gt;      dwBlobLen,&lt;br /&gt;     0,&lt;br /&gt;     0,&lt;br /&gt;     &amp;amp;hPubKey))&lt;br /&gt;    {&lt;br /&gt;      printf("The key has been imported.\n");&lt;br /&gt;    }&lt;br /&gt;    else&lt;br /&gt;    {&lt;br /&gt;      printf("Public key import failed.\n");&lt;br /&gt;     exit(1);&lt;br /&gt;    }&lt;/p&gt; &lt;p&gt;    // Not this one&lt;br /&gt;    //if (!CryptSetKeyParam(UserKey, KP_CERTIFICATE,  pCertContext-&amp;gt;pbCertEncoded, 0))&lt;br /&gt;    if (!CryptSetKeyParam(hPubKey,  KP_CERTIFICATE, pCertContext-&amp;gt;pbCertEncoded, 0))&lt;br /&gt;    {&lt;br /&gt;    &lt;br /&gt;      error = GetLastError();&lt;br /&gt;     printf("CryptSetKeyParam 0x%x\n", error);&lt;/p&gt; &lt;p&gt;     if (error != NTE_BAD_TYPE) {&lt;br /&gt;      // If error is bad_type then we  just can't set the property.&lt;br /&gt;      // Likely means our provider isn't a smart  card.&lt;br /&gt;      // If there was another error, we should report it.&lt;br /&gt;       printf("CryptSetKeyParam Failed (0x80090020 usually means no room on card)  0x%x\n",error);&lt;/p&gt; &lt;p&gt;     }&lt;br /&gt;    } &lt;/p&gt; &lt;p&gt;    if(hPubKey) { &lt;br /&gt;     CryptDestroyKey(hPubKey); &lt;br /&gt;    }&lt;/p&gt; &lt;p&gt;     //--------------------------------------------------------------------&lt;br /&gt;    //  Allocate memory for the pbKeyBlob.&lt;br /&gt;    if(pbKeyBlob)&lt;br /&gt;      free(pbKeyBlob);&lt;/p&gt; &lt;p&gt;   }&lt;br /&gt;   else&lt;br /&gt;   {&lt;br /&gt;    printf("CertGetName failed. \n");&lt;br /&gt;   }&lt;/p&gt; &lt;p&gt;   CertFreeCertificateContext(pCertContext);&lt;/p&gt; &lt;p&gt;} // End of while&lt;br /&gt;}&lt;/p&gt; &lt;p&gt;void InstallPfx(CHAR *filename, CHAR *password)&lt;br /&gt;{&lt;br /&gt;HANDLE hFile;&lt;br /&gt;BOOL  bResult;&lt;br /&gt;BYTE inBuffer[10000];&lt;br /&gt;DWORD nBytesToRead = 0;&lt;br /&gt;DWORD  nBytesRead;&lt;/p&gt; &lt;p&gt;WCHAR wszpassword[20];&lt;br /&gt;HCERTSTORE pfxcert = NULL;&lt;/p&gt; &lt;p&gt;hFile = CreateFile(filename,   // open MYFILE.TXT &lt;br /&gt;    GENERIC_READ,              // open for reading &lt;br /&gt;   FILE_SHARE_READ,            // share for reading &lt;br /&gt;   NULL,                      // no security &lt;br /&gt;    OPEN_EXISTING,             // existing file only &lt;br /&gt;    FILE_ATTRIBUTE_NORMAL,     // normal file &lt;br /&gt;   NULL);                     //  no attr. template&lt;/p&gt; &lt;p&gt;if (hFile == INVALID_HANDLE_VALUE) &lt;br /&gt;{ &lt;br /&gt;   printf("Could not open  file.\n");   // process error &lt;br /&gt;   return;&lt;br /&gt;}&lt;/p&gt; &lt;p&gt;nBytesToRead = GetFileSize (hFile, NULL);&lt;/p&gt; &lt;p&gt;printf("File Size is %d\n", nBytesToRead);&lt;/p&gt; &lt;p&gt;bResult = ReadFile(hFile, &amp;amp;inBuffer, nBytesToRead, &amp;amp;nBytesRead, NULL)  ; &lt;br /&gt;&lt;br /&gt;if (bResult) // Reading is OK.&lt;br /&gt;{ &lt;br /&gt;   CRYPT_DATA_BLOB  pfxblob;&lt;br /&gt;   pfxblob.cbData = nBytesRead;&lt;br /&gt;   pfxblob.pbData = inBuffer;&lt;/p&gt; &lt;p&gt;   if( PFXIsPFXBlob( &amp;amp;pfxblob) )&lt;br /&gt;   {&lt;br /&gt;    printf("It's a Pfx  Certificate.\n");&lt;/p&gt; &lt;p&gt;    MultiByteToWideChar( CP_ACP, 0, password,&lt;br /&gt;     strlen(password)+1,  wszpassword,   &lt;br /&gt;     sizeof(wszpassword)/sizeof(wszpassword[0]) );&lt;/p&gt; &lt;p&gt;    if( NULL != PFXImportCertStore(&lt;br /&gt;     &amp;amp;pfxblob,&lt;br /&gt;      wszpassword,&lt;br /&gt;     0x21    //CRYPT_USER_PROTECTED&lt;br /&gt;     )&lt;br /&gt;     )&lt;br /&gt;     {&lt;br /&gt;     printf("It's a Pfx imPORT OK.\n");&lt;/p&gt; &lt;p&gt;     pfxcert = PFXImportCertStore(&lt;br /&gt;      &amp;amp;pfxblob,&lt;br /&gt;       wszpassword,&lt;br /&gt;      0x21    //CRYPT_USER_PROTECTED&lt;br /&gt;      );&lt;/p&gt; &lt;p&gt;     ToSmartCard(pfxcert); &lt;/p&gt; &lt;p&gt;     // 列出所有My的证书&lt;br /&gt;     //ToSmartCard(hSystemStore);&lt;/p&gt; &lt;p&gt;    }&lt;/p&gt; &lt;p&gt;   }&lt;br /&gt;}&lt;/p&gt; &lt;p&gt;CloseHandle(hFile);&lt;br /&gt;}&lt;/p&gt; &lt;p&gt;void OpenCert(HCRYPTPROV  hprov)&lt;br /&gt;{&lt;br /&gt;//--------------------------------------------------------------------&lt;br /&gt;//  Declare and initialize variables.&lt;/p&gt; &lt;p&gt;HCERTSTORE hSystemStore;              // system store handle&lt;/p&gt; &lt;p&gt;//--------------------------------------------------------------------&lt;br /&gt;//  Open the MY system certificate store. The same call can be&lt;br /&gt;// used with the  name of a different system store, such as My or Root,&lt;br /&gt;// as the second  parameter.&lt;/p&gt; &lt;p&gt;if(hSystemStore = CertOpenSystemStore(&lt;br /&gt;   hprov,&lt;br /&gt;   "MY"))&lt;br /&gt;{&lt;br /&gt;    printf("The MY system store is open. Continue.\n");&lt;br /&gt;}&lt;br /&gt;else&lt;br /&gt;{&lt;br /&gt;    printf("The MY system store did not open.\n");&lt;br /&gt;   exit(1);&lt;br /&gt;}&lt;/p&gt; &lt;p&gt;// Use the store as needed.&lt;br /&gt;// ...&lt;/p&gt; &lt;p&gt;InstallPfx("d:\\exported.pfx", "123456");&lt;/p&gt; &lt;p&gt;// When done using the store, close  it.&lt;br /&gt;if(!CertCloseStore(hSystemStore,CERT_CLOSE_STORE_CHECK_FLAG))&lt;br /&gt;{&lt;br /&gt;    printf("Unable to close the MY system store.\n");&lt;br /&gt;   exit(1);&lt;br /&gt;}&lt;br /&gt;}&lt;/p&gt; &lt;p&gt;int main(int argc, CHAR* argv[])&lt;br /&gt;{&lt;/p&gt; &lt;p&gt;//--------------------------------------------------------------------&lt;br /&gt;//  Declare and initialize variables.&lt;/p&gt; &lt;p&gt;// provider context.&lt;br /&gt;LPCSTR UserName = "MyKeyContainer"; // Name of the  key container&lt;br /&gt;LPCSTR ProviderName = "eSafe Cryptographic Service Provider  v2.0";&lt;/p&gt; &lt;p&gt;&lt;br /&gt;// to be  used.&lt;br /&gt;//--------------------------------------------------------------------&lt;br /&gt;//  Attempt to acquire a context and a key&lt;br /&gt;// container. The context will use the  default CSP&lt;br /&gt;// for the RSA_FULL provider type. DwFlags is set to 0&lt;br /&gt;// to  attempt to open an existing key container.&lt;/p&gt; &lt;p&gt;if(CryptAcquireContext(&lt;br /&gt;   &amp;amp;hCryptProv,               // Handle to the  CSP&lt;br /&gt;   UserName,                  // Container name &lt;br /&gt;    ProviderName,              // Use the default provider&lt;br /&gt;    PROV_RSA_FULL,             // Provider type&lt;br /&gt;   0))                        //  Flag values&lt;br /&gt;{&lt;br /&gt;   printf("A crypto context with the %s key container \n",  UserName);&lt;br /&gt;   printf("has been acquired.\n\n");&lt;/p&gt; &lt;p&gt;   OpenCert(hCryptProv);&lt;/p&gt; &lt;p&gt;}&lt;br /&gt;else&lt;br /&gt;{ &lt;br /&gt;    //--------------------------------------------------------------------&lt;br /&gt;   //  An error occurred in acquiring the context. This could mean&lt;br /&gt;   // that the  key container requested does not exist. In this case,&lt;br /&gt;   // the function can  be called again to attempt to create a new key &lt;br /&gt;   // container. Error codes  are defined in winerror.h.&lt;br /&gt;   if (GetLastError() == NTE_BAD_KEYSET)&lt;br /&gt;   {  &lt;br /&gt;    if(CryptAcquireContext(&lt;br /&gt;     &amp;amp;hCryptProv, &lt;br /&gt;     UserName,  &lt;br /&gt;     ProviderName, &lt;br /&gt;     PROV_RSA_FULL, &lt;br /&gt;     CRYPT_NEWKEYSET))  &lt;br /&gt;    {&lt;br /&gt;     printf("A new key container has been created.\n");&lt;br /&gt;      OpenCert(hCryptProv);&lt;br /&gt;    }&lt;br /&gt;    else&lt;br /&gt;    {&lt;br /&gt;     printf("Could not  create a new key container.\n");&lt;br /&gt;     exit(1);&lt;br /&gt;    }&lt;br /&gt;   }&lt;br /&gt;    else&lt;br /&gt;   {&lt;br /&gt;    printf("A cryptographic service handle could not be  acquired.\n");&lt;br /&gt;    exit(1);&lt;br /&gt;   }&lt;/p&gt; &lt;p&gt;} // End of  else&lt;br /&gt;&lt;br /&gt;//--------------------------------------------------------------------&lt;br /&gt;//  A cryptographic context and a key container is available. Perform&lt;br /&gt;// any  functions that require a Cryptographic provider handle.&lt;/p&gt; &lt;p&gt;//--------------------------------------------------------------------&lt;br /&gt;//  When the handle is no longer needed, it must be released.&lt;/p&gt; &lt;p&gt;if (CryptReleaseContext(hCryptProv,0))&lt;br /&gt;{&lt;br /&gt;   printf("The handle has been  released.\n");&lt;br /&gt;}&lt;br /&gt;else&lt;br /&gt;{&lt;br /&gt;   printf("The handle could not be  released.\n");&lt;br /&gt;}&lt;/p&gt; &lt;p&gt;&lt;br /&gt;return 0;&lt;br /&gt;}&lt;/p&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/adylee/aggbug/2320783.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/adylee/archive/2012/01/12/2320783.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/adylee/archive/2012/01/12/2320778.html</id><title type="text">[转]通过CSP读取证书</title><summary type="text">1. 通过Csp读取证书使用的函数 CryptGetUserKey 获取公私钥对的句柄 注意AT_SIGNATURE，AT_KEYEXCHANGE的不同，前者签名，后者加密。 CryptGetKeyParam 读取和公私钥对相关联的证书 注意使用KP_CERTIFICATE 2. 指定Csp容器 通常获取证书时，usbkey已经发证完毕。这是比较难以判断容器的名称。通常会选择默认容器，但有些RA发证时比较特别，可能会使用两个容器。签名证书使用默认容器，而加密证书使用指定的某个容器。 为了验证上面所说的情况，需要枚举Usbkey上的容器进行选择查看。 CryptGetProv...</summary><published>2012-01-12T08:30:00Z</published><updated>2012-01-12T08:30:00Z</updated><author><name>Ady Lee</name><uri>http://www.cnblogs.com/adylee/</uri></author><link rel="alternate" href="http://www.cnblogs.com/adylee/archive/2012/01/12/2320778.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/adylee/archive/2012/01/12/2320778.html"/><content type="html">&lt;div&gt;&lt;p&gt;1. 通过Csp读取证书使用的函数&lt;/p&gt; &lt;p&gt;CryptGetUserKey   &lt;/p&gt; &lt;p&gt;获取公私钥对的句柄&lt;/p&gt; &lt;p&gt;注意AT_SIGNATURE，AT_KEYEXCHANGE的不同，前者签名，后者加密。&lt;/p&gt; &lt;p&gt;CryptGetKeyParam   &lt;/p&gt; &lt;p&gt;读取和公私钥对相关联的证书&lt;/p&gt; &lt;p&gt;注意使用&lt;span&gt;KP_CERTIFICATE  &lt;/span&gt;&lt;/p&gt;  &lt;p&gt;2. 指定Csp容器&lt;/p&gt; &lt;p&gt;通常获取证书时，usbkey已经发证完毕。这是比较难以判断容器的名称。通常会选择默认容器，但有些RA发证时比较特别，可能会使用两个容器。签名证书使用默认容器，而加密证书使用指定的某个容器。&lt;/p&gt;  &lt;p&gt;为了验证上面所说的情况，需要枚举Usbkey上的容器进行选择查看。&lt;/p&gt; &lt;p&gt;CryptGetProvParam&lt;/p&gt; &lt;p&gt;注意：  第二个参数使用PP_ENUMCONTAINERS&lt;/p&gt; &lt;p&gt;获取第一个容器名称的时候，最后的参数使用CRYPT_FIRST&lt;/p&gt; &lt;p&gt;接下去，调用时使用最后的参数CRYPT_NEXT，当GetLastError的值等于ERROR_NO_MORE_ITEMS则表示没有容器了。&lt;/p&gt;  &lt;p&gt;指定好了容器名称后再进行证书的读取工作，下面列出了程序运行结果：&lt;/p&gt; &lt;p&gt;签名证书容器&lt;/p&gt;&lt;span&gt; &lt;div style="border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; padding-bottom: 1pt; padding-left: 4pt; padding-right: 4pt; background: silver; border-top: windowtext 1pt solid; border-right: windowtext 1pt solid; padding-top: 1pt"&gt; &lt;p&gt;&lt;span&gt;A crypto context with the  MyKeyContainer key container&lt;/span&gt;&lt;/p&gt; &lt;p&gt;has been acquired.&lt;/p&gt;  &lt;p&gt;&lt;span&gt;0. ContainName is  3d06503f-e4ed-4e89-8d56-2960aa5f0364&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span&gt;1. ContainName is  KOAL_CSP_WRAPPER_CONTAINER&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span&gt;2. ContainName is  J&lt;/span&gt;&lt;/p&gt; &lt;p&gt;The handle has been released.&lt;/p&gt; &lt;p&gt;&lt;span&gt;Please select a  container:&lt;/span&gt;&lt;/p&gt; &lt;p&gt;0&lt;/p&gt; &lt;p&gt;&lt;span&gt;A crypto context with the  3d06503f-e4ed-4e89-8d56-2960aa5f0364 key container&lt;/span&gt;&lt;/p&gt; &lt;p&gt;has been acquired.&lt;/p&gt;  &lt;p&gt;&lt;span&gt;Encrypt  Certification:&lt;/span&gt;&lt;/p&gt; &lt;p&gt;Invalid parameter&lt;/p&gt; &lt;p&gt;&lt;span&gt;CryptGetKeyParam Failed  0x57&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span&gt;Sign  Certification:&lt;/span&gt;&lt;/p&gt; &lt;p&gt;CertLen is 791&lt;/p&gt; &lt;p&gt;&lt;span&gt;A new certificate as been  created.&lt;/span&gt;&lt;/p&gt; &lt;p&gt;测试&lt;span&gt;  310103198301011234&lt;/span&gt;&lt;/p&gt; &lt;p&gt;SANCA&lt;/p&gt; &lt;p&gt;&lt;span&gt;The handle has been  released.&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/span&gt;  &lt;p&gt;加密证书容器&lt;/p&gt; &lt;div style="border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; padding-bottom: 1pt; padding-left: 4pt; padding-right: 4pt; background: silver; border-top: windowtext 1pt solid; border-right: windowtext 1pt solid; padding-top: 1pt"&gt; &lt;p&gt;&lt;span&gt;A crypto context with the  MyKeyContainer key container&lt;/span&gt;&lt;/p&gt; &lt;p&gt;has been acquired.&lt;/p&gt;  &lt;p&gt;&lt;span&gt;0. ContainName is  3d06503f-e4ed-4e89-8d56-2960aa5f0364&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span&gt;1. ContainName is  KOAL_CSP_WRAPPER_CONTAINER&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span&gt;2. ContainName is  J&lt;/span&gt;&lt;/p&gt; &lt;p&gt;The handle has been released.&lt;/p&gt; &lt;p&gt;&lt;span&gt;Please select a  container:&lt;/span&gt;&lt;/p&gt; &lt;p&gt;1&lt;/p&gt; &lt;p&gt;&lt;span&gt;A crypto context with the  KOAL_CSP_WRAPPER_CONTAINER key container&lt;/span&gt;&lt;/p&gt; &lt;p&gt;has been acquired.&lt;/p&gt;  &lt;p&gt;&lt;span&gt;Encrypt  Certification:&lt;/span&gt;&lt;/p&gt; &lt;p&gt;CertLen is 759&lt;/p&gt; &lt;p&gt;&lt;span&gt;A new certificate as been  created.&lt;/span&gt;&lt;/p&gt; &lt;p&gt;测试&lt;span&gt;  310103198301011234&lt;/span&gt;&lt;/p&gt; &lt;p&gt;SANCA&lt;/p&gt; &lt;p&gt;&lt;span&gt;Sign  Certification:&lt;/span&gt;&lt;/p&gt; &lt;p&gt;Invalid parameter&lt;/p&gt; &lt;p&gt;&lt;span&gt;CryptGetKeyParam Failed  0x57&lt;/span&gt;&lt;/p&gt; &lt;p&gt;The handle has been released.&lt;/p&gt; &lt;/div&gt; &lt;p&gt;3. 相关代码&lt;/p&gt; &lt;p&gt;// getPubKey.cpp : 定义控制台应用程序的入口点。&lt;br /&gt;//&lt;/p&gt; &lt;p&gt;#include "stdafx.h"&lt;br /&gt;#include &amp;lt;windows.h&amp;gt;&lt;br /&gt;#include  &amp;lt;WinCrypt.h&amp;gt;&lt;br /&gt;#include &amp;lt;stdio.h&amp;gt;&lt;/p&gt; &lt;p&gt;#include &amp;lt;vector&amp;gt;&lt;br /&gt;#include &amp;lt;string&amp;gt;&lt;/p&gt; &lt;p&gt;using namespace std;&lt;/p&gt; &lt;p&gt;vector&amp;lt;string&amp;gt; contain_vector;&lt;/p&gt; &lt;p&gt;//CRYPT_DELETEKEYSET&lt;/p&gt; &lt;p&gt;int TestEnumContainers(HCRYPTPROV hCryptProv)&lt;br /&gt;{&lt;br /&gt;BYTE    pbData[1000];       // 1000 will hold the longest &lt;br /&gt;DWORD cbData =  1000;&lt;br /&gt;int count = 0;&lt;/p&gt; &lt;p&gt;if ( CryptGetProvParam(&lt;br /&gt;   hCryptProv, &lt;br /&gt;    PP_ENUMCONTAINERS, &lt;br /&gt;   (BYTE *)&amp;amp;pbData,&lt;br /&gt;   &amp;amp;cbData, &lt;br /&gt;    CRYPT_FIRST))&lt;br /&gt;{&lt;br /&gt;   pbData[cbData] = '\0';&lt;br /&gt;   printf("%d. ContainName is  %s\n", count++, pbData);&lt;br /&gt;   contain_vector.push_back((char *)pbData);&lt;/p&gt; &lt;p&gt;   pbData[0] = '\0';&lt;br /&gt;   cbData = 1000;&lt;/p&gt; &lt;p&gt;   while( CryptGetProvParam(&lt;br /&gt;    hCryptProv, &lt;br /&gt;     PP_ENUMCONTAINERS, &lt;br /&gt;    (BYTE *)&amp;amp;pbData,&lt;br /&gt;    &amp;amp;cbData, &lt;br /&gt;     CRYPT_NEXT)&lt;br /&gt;    )&lt;br /&gt;   {&lt;br /&gt;    if( ERROR_NO_MORE_ITEMS ==  GetLastError())&lt;br /&gt;    {&lt;br /&gt;     break;&lt;br /&gt;    }&lt;/p&gt; &lt;p&gt;    pbData[cbData] = '\0';&lt;br /&gt;    printf("%d. ContainName is  %s\n", count++, pbData);&lt;br /&gt;    contain_vector.push_back((char *)pbData);&lt;br /&gt;     pbData[0] = '\0';&lt;br /&gt;    cbData = 1000;&lt;br /&gt;   }&lt;/p&gt; &lt;p&gt;}&lt;/p&gt; &lt;p&gt;return count;&lt;br /&gt;}&lt;/p&gt; &lt;p&gt;int  EnumContainers()&lt;br /&gt;{&lt;br /&gt;//--------------------------------------------------------------------&lt;br /&gt;//  Declare and initialize variables.&lt;br /&gt;HCRYPTPROV hCryptProv = NULL;        //  Handle for a cryptographic&lt;/p&gt; &lt;p&gt;// provider context.&lt;br /&gt;LPCSTR UserName = "MyKeyContainer"; //  Name of the key container&lt;br /&gt;LPCSTR ProviderName = "eSafe Cryptographic Service  Provider v2.0";&lt;/p&gt; &lt;p&gt;int count = -1;&lt;/p&gt; &lt;p&gt;// to be  used.&lt;br /&gt;//--------------------------------------------------------------------&lt;br /&gt;//  Attempt to acquire a context and a key&lt;br /&gt;// container. The context will use the  default CSP&lt;br /&gt;// for the RSA_FULL provider type. DwFlags is set to 0&lt;br /&gt;// to  attempt to open an existing key container.&lt;/p&gt; &lt;p&gt;if(CryptAcquireContext(&lt;br /&gt;   &amp;amp;hCryptProv,               //  Handle to the CSP&lt;br /&gt;   NULL,        // Container name &lt;br /&gt;    ProviderName,              // Use the default provider&lt;br /&gt;    PROV_RSA_FULL,             // Provider type&lt;br /&gt;   0))                        //  Flag values&lt;br /&gt;{&lt;br /&gt;   printf("A crypto context with the %s key container \n",  UserName);&lt;br /&gt;   printf("has been acquired.\n\n");&lt;/p&gt; &lt;p&gt;   count = TestEnumContainers(hCryptProv); &lt;/p&gt; &lt;p&gt;}&lt;br /&gt;else&lt;br /&gt;{ &lt;br /&gt;    //--------------------------------------------------------------------&lt;br /&gt;   //  An error occurred in acquiring the context. This could mean&lt;br /&gt;   // that the  key container requested does not exist. In this case,&lt;br /&gt;   // the function can  be called again to attempt to create a new key &lt;br /&gt;   // container. Error codes  are defined in winerror.h.&lt;br /&gt;   if (GetLastError() == NTE_BAD_KEYSET)&lt;br /&gt;   {  &lt;br /&gt;    if(CryptAcquireContext(&lt;br /&gt;     &amp;amp;hCryptProv, &lt;br /&gt;     NULL, &lt;br /&gt;      ProviderName, &lt;br /&gt;     PROV_RSA_FULL, &lt;br /&gt;     CRYPT_NEWKEYSET)) &lt;br /&gt;     {&lt;br /&gt;     printf("A new key container has been created.\n");&lt;br /&gt;     count =  TestEnumContainers(hCryptProv); &lt;br /&gt;    }&lt;br /&gt;    else&lt;br /&gt;    {&lt;br /&gt;      printf("Could not create a new key container.\n");&lt;br /&gt;     exit(1);&lt;br /&gt;     }&lt;br /&gt;   }&lt;br /&gt;   else&lt;br /&gt;   {&lt;br /&gt;    printf("A cryptographic service handle could  not be acquired.\n");&lt;br /&gt;    exit(1);&lt;br /&gt;   }&lt;/p&gt; &lt;p&gt;} // End of else&lt;/p&gt; &lt;p&gt;//--------------------------------------------------------------------&lt;br /&gt;//  A cryptographic context and a key container is available. Perform&lt;br /&gt;// any  functions that require a Cryptographic provider handle.&lt;/p&gt; &lt;p&gt;//--------------------------------------------------------------------&lt;br /&gt;//  When the handle is no longer needed, it must be released.&lt;/p&gt; &lt;p&gt;if (CryptReleaseContext(hCryptProv,0))&lt;br /&gt;{&lt;br /&gt;   printf("The  handle has been released.\n");&lt;br /&gt;}&lt;br /&gt;else&lt;br /&gt;{&lt;br /&gt;   printf("The handle could  not be released.\n");&lt;br /&gt;}&lt;/p&gt; &lt;p&gt;return count;&lt;br /&gt;}&lt;/p&gt; &lt;p&gt;&lt;br /&gt;void DecodePubKey(HCRYPTPROV hCryptProv, DWORD  dwKeySpec)&lt;br /&gt;{&lt;br /&gt;HCRYPTKEY hCurKey= 0;&lt;br /&gt;BOOL ret=TRUE;&lt;br /&gt;//&lt;br /&gt;// Check if  a key already exisis, &lt;br /&gt;// If it don't generate a  key!&lt;br /&gt;///////////////////////////////////////////&lt;br /&gt;if  (!CryptGetUserKey(hCryptProv, dwKeySpec, &amp;amp;hCurKey))&lt;br /&gt;{&lt;br /&gt;   int error =  GetLastError();&lt;br /&gt;   // Make sure error is no key.&lt;br /&gt;   if (error !=  NTE_NO_KEY) &lt;br /&gt;   {&lt;br /&gt;    printf("First Call to CryptGenKey Failed- with error  other than NTE_NO_KEY: [0x%X]\n",error);&lt;br /&gt;    ret=FALSE;&lt;br /&gt;    goto  done;&lt;br /&gt;   }&lt;br /&gt;}&lt;/p&gt; &lt;p&gt;unsigned char uchCertInfo[2000];&lt;br /&gt;DWORD CertLen =  2000;&lt;br /&gt;DWORD error = 0;&lt;/p&gt; &lt;p&gt;if (!CryptGetKeyParam(hCurKey, KP_CERTIFICATE, uchCertInfo,  &amp;amp;CertLen , 0))&lt;br /&gt;{&lt;/p&gt; &lt;p&gt;   //ERROR_MORE_DATA&lt;/p&gt; &lt;p&gt;&lt;br /&gt;   error = GetLastError();&lt;/p&gt; &lt;p&gt;   if( ERROR_INVALID_PARAMETER == error)&lt;br /&gt;   {&lt;br /&gt;     printf("Invalid parameter\n");&lt;br /&gt;   }&lt;/p&gt; &lt;p&gt;   if (error != NTE_BAD_TYPE) {&lt;br /&gt;    // If error is bad_type  then we just can't set the property.&lt;br /&gt;    // Likely means our provider isn't a  smart card.&lt;br /&gt;    // If there was another error, we should report it.&lt;br /&gt;     printf("CryptGetKeyParam Failed 0x%x\n",error);&lt;br /&gt;   }&lt;br /&gt;   ret=FALSE;&lt;br /&gt;    goto done;&lt;br /&gt;}&lt;/p&gt; &lt;p&gt;printf("CertLen is %d\n", CertLen );&lt;/p&gt; &lt;p&gt;&lt;br /&gt;// MAKING X509 CERTIFICATE&lt;/p&gt; &lt;p&gt;#define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING |  X509_ASN_ENCODING)&lt;br /&gt;PCCERT_CONTEXT pCertContext = NULL;&lt;/p&gt; &lt;p&gt;//------------------------------------------------------------------  &lt;br /&gt;// Create a new certificate from the encoded part of&lt;br /&gt;// an available  certificate. pDesiredCert is a previously&lt;br /&gt;// assigned PCCERT_CONTEXT  variable.&lt;br /&gt;if(pCertContext = CertCreateCertificateContext(&lt;br /&gt;    MY_ENCODING_TYPE,              // The encoding type&lt;br /&gt;   uchCertInfo,   // The  encoded data from&lt;br /&gt;   // the certificate retrieved&lt;br /&gt;   CertLen)) // The  length of the encoded data&lt;br /&gt;{&lt;br /&gt;   printf("A new certificate as been  created.\n");&lt;/p&gt; &lt;p&gt;   // Use the certificate context as needed.&lt;br /&gt;   // ...&lt;/p&gt; &lt;p&gt;   CHAR pszBuff[256];&lt;br /&gt;   CertGetNameString(pCertContext,  CERT_NAME_SIMPLE_DISPLAY_TYPE,&lt;br /&gt;    0, NULL, pszBuff, 128);&lt;br /&gt;    printf("%s\n", pszBuff); // 显示名&lt;br /&gt;   CertGetNameString(pCertContext,  CERT_NAME_SIMPLE_DISPLAY_TYPE,&lt;br /&gt;    CERT_NAME_ISSUER_FLAG, NULL, pszBuff,  128);&lt;br /&gt;   printf("%s\n", pszBuff); // 颁发者&lt;/p&gt; &lt;p&gt;   // When finished, free the certificate context.&lt;br /&gt;    CertFreeCertificateContext(pCertContext);&lt;br /&gt;}&lt;br /&gt;else&lt;br /&gt;{&lt;br /&gt;   printf("A new  certificate could not be created.\n");&lt;br /&gt;   goto done;&lt;br /&gt;}&lt;/p&gt; &lt;p&gt;done:&lt;br /&gt;if (hCurKey) CryptDestroyKey(hCurKey);&lt;br /&gt;}&lt;/p&gt; &lt;p&gt;void GetPublicKey(const char  *ContainName)&lt;br /&gt;{&lt;br /&gt;//--------------------------------------------------------------------&lt;br /&gt;//  Declare and initialize variables.&lt;br /&gt;HCRYPTPROV hCryptProv = NULL;        //  Handle for a cryptographic&lt;/p&gt; &lt;p&gt;// provider context.&lt;br /&gt;LPCSTR ProviderName = "eSafe  Cryptographic Service Provider v2.0";&lt;/p&gt; &lt;p&gt;&lt;br /&gt;// to be  used.&lt;br /&gt;//--------------------------------------------------------------------&lt;br /&gt;//  Attempt to acquire a context and a key&lt;br /&gt;// container. The context will use the  default CSP&lt;br /&gt;// for the RSA_FULL provider type. DwFlags is set to 0&lt;br /&gt;// to  attempt to open an existing key container.&lt;/p&gt; &lt;p&gt;if(CryptAcquireContext(&lt;br /&gt;   &amp;amp;hCryptProv,               //  Handle to the CSP&lt;br /&gt;   ContainName,      // Container name &lt;br /&gt;    ProviderName,              // Use the default provider&lt;br /&gt;    PROV_RSA_FULL,             // Provider type&lt;br /&gt;   0))                        //  Flag values&lt;br /&gt;{&lt;br /&gt;   printf("A crypto context with the %s key container \n",  ContainName);&lt;br /&gt;   printf("has been acquired.\n\n");&lt;/p&gt; &lt;p&gt;&lt;br /&gt;   printf("Encrypt Certification:\n");&lt;br /&gt;    DecodePubKey(hCryptProv, AT_KEYEXCHANGE);&lt;/p&gt; &lt;p&gt;   printf("Sign Certification:\n");&lt;br /&gt;    DecodePubKey(hCryptProv, AT_SIGNATURE);&lt;/p&gt; &lt;p&gt;&lt;br /&gt;}&lt;br /&gt;else&lt;br /&gt;{ &lt;br /&gt;    //--------------------------------------------------------------------&lt;br /&gt;   //  An error occurred in acquiring the context. This could mean&lt;br /&gt;   // that the  key container requested does not exist. In this case,&lt;br /&gt;   // the function can  be called again to attempt to create a new key &lt;br /&gt;   // container. Error codes  are defined in winerror.h.&lt;br /&gt;   if (GetLastError() == NTE_BAD_KEYSET)&lt;br /&gt;   {  &lt;br /&gt;    if(CryptAcquireContext(&lt;br /&gt;     &amp;amp;hCryptProv, &lt;br /&gt;     ContainName,  &lt;br /&gt;     ProviderName, &lt;br /&gt;     PROV_RSA_FULL, &lt;br /&gt;     CRYPT_NEWKEYSET))  &lt;br /&gt;    {&lt;br /&gt;     printf("A new key container has been created.\n");&lt;br /&gt;     }&lt;br /&gt;    else&lt;br /&gt;    {&lt;br /&gt;     printf("Could not create a new key  container.\n");&lt;br /&gt;     exit(1);&lt;br /&gt;    }&lt;br /&gt;   }&lt;br /&gt;   else&lt;br /&gt;   {&lt;br /&gt;     printf("A cryptographic service handle could not be acquired.\n");&lt;br /&gt;     exit(1);&lt;br /&gt;   }&lt;/p&gt; &lt;p&gt;} // End of else&lt;/p&gt; &lt;p&gt;//--------------------------------------------------------------------&lt;br /&gt;//  A cryptographic context and a key container is available. Perform&lt;br /&gt;// any  functions that require a Cryptographic provider handle.&lt;/p&gt; &lt;p&gt;//--------------------------------------------------------------------&lt;br /&gt;//  When the handle is no longer needed, it must be released.&lt;/p&gt; &lt;p&gt;if (CryptReleaseContext(hCryptProv,0))&lt;br /&gt;{&lt;br /&gt;   printf("The  handle has been released.\n");&lt;br /&gt;}&lt;br /&gt;else&lt;br /&gt;{&lt;br /&gt;   printf("The handle could  not be released.\n");&lt;br /&gt;}&lt;br /&gt;}&lt;/p&gt; &lt;p&gt;int main(int argc, CHAR* argv[])&lt;br /&gt;{&lt;/p&gt; &lt;p&gt;int count = EnumContainers();&lt;br /&gt;int selectno;&lt;/p&gt; &lt;p&gt;&lt;br /&gt;printf("Please select a container:\n");&lt;br /&gt;scanf("%d",  &amp;amp;selectno);&lt;br /&gt;if( selectno &amp;lt;= count )&lt;br /&gt;{&lt;br /&gt;    GetPublicKey(contain_vector[selectno].c_str());&lt;br /&gt;}&lt;/p&gt; &lt;p&gt;// 0. ContainName is 3d06503f-e4ed-4e89-8d56-2960aa5f0364&lt;br /&gt;//  签名证书&lt;/p&gt; &lt;p&gt;// 1. ContainName is KOAL_CSP_WRAPPER_CONTAINER&lt;br /&gt;// 加密证书&lt;/p&gt; &lt;p&gt;return 0;&lt;br /&gt;}&lt;/p&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/adylee/aggbug/2320778.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/adylee/archive/2012/01/12/2320778.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/adylee/archive/2012/01/12/2320769.html</id><title type="text">[转]Windows密钥容器和证书的关系</title><summary type="text">其实CSP主要是对容器里的密钥对操作的，和证书关系不大。容器里的密钥对有两种类型：一种是AT_KEYEXCHANGE，表示加密的密钥对，一种是AT_SIGNATURE表示签名的密钥对。由于美国的出口限制，在MS的CSP中加密的密钥对可以取的密钥最大长度通常会比签名的密钥对短。通常加密的密钥对只会用于加密，签名的密钥对只会用于签名，由于某些原因（例如产生证书请求），加密的密钥对也可以用于签名。我把AT_KEYEXCHANGE和AT_SIGNATURE看作是容器里的两个位置。在智能卡CSP中可以把证书写入容器中，和加密的密钥对对应的证书写到AT_KEYEXCHANGE位置中，和签名的密钥对对应的证</summary><published>2012-01-12T08:28:00Z</published><updated>2012-01-12T08:28:00Z</updated><author><name>Ady Lee</name><uri>http://www.cnblogs.com/adylee/</uri></author><link rel="alternate" href="http://www.cnblogs.com/adylee/archive/2012/01/12/2320769.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/adylee/archive/2012/01/12/2320769.html"/><content type="html">&lt;div&gt;&lt;div&gt;其实CSP主要是对容器里的密钥对操作的，和证书关系不大。&lt;/div&gt;&lt;div&gt;容器里的密钥对有两种类型：一种是&lt;span style="color: #ff0000;"&gt;AT_KEYEXCHANGE&lt;/span&gt;，表示加密的密钥对，一种是&lt;span style="color: #ff0000;"&gt;AT_SIGNATURE&lt;/span&gt;表示签名的密钥对。&lt;/div&gt;&lt;div&gt;由于美国的出口限制，&lt;span style="color: #0000ff;"&gt;在MS的CSP中加密的密钥对可以取的密钥最大长度通常会比签名的密钥对短&lt;/span&gt;。&lt;/div&gt;&lt;div&gt;通常加密的密钥对只会用于加密，签名的密钥对只会用于签名，由于某些原因（例如产生证书请求），加密的密钥对也可以用于签名。&lt;/div&gt;&lt;div&gt;我把AT_KEYEXCHANGE和AT_SIGNATURE看作是容器里的两个位置。在智能卡CSP中可以把证书写入容器中，和加密的密钥对对应的证书写到AT_KEYEXCHANGE位置中，和签名的密钥对对应的证书写到AT_SIGNATURE位置中。这里判断依据是证书的公钥和密钥对的公钥相同，而不是证书中的密钥用法扩展。&lt;/div&gt;&lt;div&gt;使用Crypto API可以根据证书库里的证书的&lt;span style="color: #0000ff;"&gt;CERT_KEY_PROV_INFO_PROP_ID&lt;/span&gt;找到相对应得容器里的密钥对。&lt;span style="color: #0000ff;"&gt;CRYPT_KEY_PROV_INFO&lt;/span&gt;中的&lt;span style="color: #0000ff;"&gt;dwKeySpec&lt;/span&gt;就是指容器里的密钥对类型。如果在CSP实现的层次根据证书的密钥用法扩展来限制是否能够加密和签名，要先读出证书，这个操作比较慢，估计实现者比较少采用。&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;&lt;span style="color: #808080;"&gt;事实上，明华EKey的CSP的AT_KEYEXCHANGE和AT_SIGNATURE类型的密钥对都是既可以加密也可以签名的(CryptDecrypt和CryptSignHash是没问题的，没怎么测过CryptImportKey，不知道是不是签名的密钥对能不能成功导入会话密钥)。我没有和你的版本一样的xcsp_eclib.dll，我使用了一个稍微旧一点的版本的来测试。我测试了CryptDecryptMessage函数，发现如果是签名密钥对不管我证书的密钥用法扩展如何设置则解密总是会失败（用MS的CSP也一样）。而使用加密密钥对则可以成功。虽然OUTLOOK可能不是使用CryptDecryptMessage来解密CMS的EnvelopedData的，但是我相信最终都会调用CSP的CryptImportKey解出对称密钥，再解密的。CryptDecryptMessage传给CryptImportKey的是一个Simple-Key BLOBs。我的测试发现EKey好像总是使用加密的密钥对来解密。这可能是这个Simple-Key BLOBs的结构有问题导致解密失败或者EKey的CSP的CryptImportKey有BUG导致解密失败。&lt;/span&gt;&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;&lt;span style="color: #808080;"&gt;看来，如果要使得证书既能加密也能签名，必须首先保证使用的是加密密钥对。产生加密密钥对可以在产生证书请求的时候使用Xenroll来设置，至于使用PKCS#12文件导入的方式要取决于使用的软件是根据什么来判断应该创建什么类型的密钥对。&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/adylee/aggbug/2320769.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/adylee/archive/2012/01/12/2320769.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/adylee/archive/2011/06/02/2068322.html</id><title type="text">[转]boost.bind 如何 bind continue.1</title><summary type="text">我们先定义目标： 1. simple_bind 提供与 bind 类似的界面，可以只考虑通过对象引用（或者值）调用成员函数的情况，而不考虑 free function 或者通过指针调用等等。具体地说，就是允许 person.SetName("Ralph") --&gt; simple_bind(&amp;Person::SetName, person, _1)(string("Ralph")) simple_bind(&amp;Person::SetName, _1, string(“Ralph"))(person) simple_bind(&amp;</summary><published>2011-06-02T03:39:00Z</published><updated>2011-06-02T03:39:00Z</updated><author><name>Ady Lee</name><uri>http://www.cnblogs.com/adylee/</uri></author><link rel="alternate" href="http://www.cnblogs.com/adylee/archive/2011/06/02/2068322.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/adylee/archive/2011/06/02/2068322.html"/><content type="html">&lt;div&gt;&lt;p&gt;&lt;span style="font-family: 宋体;"&gt;我们先定义目标：&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;br /&gt; 1. simple_bind &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;提供与&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; bind &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;类似的界面，可以只考虑通过对象引用（或者值）调用成员函数的情况，而不考虑&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; free function &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;或者通过指针调用等等。具体地说，就是允许&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;br /&gt; &lt;span style="color: #333399;"&gt;person.SetName("Ralph")&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; --&amp;gt; simple_bind(&amp;amp;Person::SetName, person, _1)(string("Ralph"))&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;simple_bind(&amp;amp;Person::SetName, _1, string(&amp;#8220;Ralph"))(person)&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;simple_bind(&amp;amp;Person::SetName, _1, _2)(person, string("Ralph"))&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;simple_bind(&amp;amp;Person::SetName, _2, _1)(string("Ralph"), person)&lt;/span&gt;&lt;br /&gt; &lt;br /&gt; 2. &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;一个&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; simple_bind &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;表达式会&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; evaluate &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;成为一个&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; simple_binder object &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;，这是一个&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; functor &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;，如：&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;br /&gt; &lt;span style="color: #333399;"&gt;simple_bind(&amp;amp;Person::SetName, person, _1)(string("Ralph"))&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;--&amp;gt; simple_binder_obj(string("Ralph"))&lt;br /&gt; simple_bind(&amp;amp;Person::SetName, _1, _2)(person, string("Ralph")) --&amp;gt; simple_binder_obj(person, string(&amp;#8220;Ralph&amp;#8221;))&lt;/span&gt;&lt;br /&gt; &lt;br /&gt; &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;在这一头一尾，我们其实没多少选择余地，一方面我们需要提供的用户界面已经定了，另一方面需要提供的函数调用界面也基本上固定了，要玩的&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; magic &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;也就是发生在中间。&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;br /&gt; 3. &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;对于&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; placeholder &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;，前面已经说过，就用简单的解决方案：&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;span style="color: #333399;"&gt;template &amp;lt;int I&amp;gt;&lt;br /&gt; class placeholder{};&lt;br /&gt; placeholder&amp;lt;1&amp;gt; _1;&lt;br /&gt; placeholder&amp;lt;2&amp;gt; _2;&lt;br /&gt; &lt;/span&gt;...&lt;br /&gt; &lt;br /&gt; &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;有了这&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;3&lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;个出发点，现在从&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; simple_bind &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;出发，首先看看&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; simple_bind &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;应该有的形式。从前面的实验中可以看出&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;br /&gt; &lt;span style="color: #333399;"&gt;template &amp;lt;typename R, typename T, typename Arg&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;simple_binder&amp;lt;R, T, Arg&amp;gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;simple_bind( R (T::*pfn)(Arg), const Arg&amp;amp; arg, placeholder&amp;amp;)&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;{&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return simple_binder&amp;lt;R, T, Arg&amp;gt;(pfn, arg);&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;}&lt;br /&gt; &lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;这样的形式虽然方便，但却不具有&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; scalability &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;。因为&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;R (T::*pfn)(Arg) &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;的限制太大了，首先，它只针对接受一个参数的成员函数，如果要支持多个参数，你要对每个&lt;strong&gt;参数数量&lt;/strong&gt;（它有一个术语叫&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; arity&lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;）写一个重载，而这些不同&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; arity &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;还要跟&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; simple_bind &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;本身的&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; arity &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;做组合，结果是爆炸性的&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; simple_bind &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;数量。其次，参数&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; arg &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;和&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; placeholder &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;也太不灵活，前面已经看到，仅仅在两个参数的情况下，就有&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;4&lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;种组合：&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;br /&gt; &lt;span style="color: #333399;"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;simple_bind(&amp;amp;Person::SetName, _1, _2)(person, "Joy");&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; simple_bind(&amp;amp;Person::SetName, _2, _1)("Joy", person);&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;simple_bind(&amp;amp;Person::SetName, _1, "Joy")(person);&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;simple_bind(&amp;amp;Person::SetName, person, _1)("Joy");&lt;br /&gt; &lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;可想而知参数更多的时候的恐怖情景。于是我们得出结论：&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;/span&gt;&lt;strong&gt;&lt;span style="font-family: 宋体;"&gt;由于前端的调用组合太复杂，&lt;/span&gt;&lt;/strong&gt;&lt;strong&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;simple_bind &lt;/span&gt;&lt;/strong&gt;&lt;strong&gt;&lt;span style="font-family: 宋体;"&gt;的界面必须以最&lt;/span&gt;&lt;/strong&gt;&lt;strong&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; generic &lt;/span&gt;&lt;/strong&gt;&lt;strong&gt;&lt;span style="font-family: 宋体;"&gt;的方式给出，由此带来的复杂性应该留待&lt;/span&gt;&lt;/strong&gt;&lt;strong&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; simple_bind &lt;/span&gt;&lt;/strong&gt;&lt;strong&gt;&lt;span style="font-family: 宋体;"&gt;内部处理。&lt;/span&gt;&lt;/strong&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;br /&gt; &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;这是经过了实验的教训得出的结论。&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;br /&gt; &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;何谓&amp;#8220;最&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; generic&lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;&amp;#8221;？没有比这更加&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; generic &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;的了：&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;br /&gt; &lt;span style="color: #333399;"&gt;template &amp;lt;typename F, typename A1&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;simple_binder&amp;lt;unspecified&amp;gt;&lt;/span&gt;&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;simple_bind(F f, A1 a1)&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;{&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; //...&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;}&lt;br /&gt; &lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;即便如此，由于&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; C++ &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;至今还没有可变数量的模板参数，我们还是不能回避对每一个&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; arity &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;都有所定义，但是这已经把复杂度控制在&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; O(arity) &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;了：&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;br /&gt; &lt;span style="color: #333399;"&gt;template &amp;lt;typename F, typename A1, typename A2&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;simple_binder&amp;lt;unspecified&amp;gt;&lt;/span&gt;&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;simple_bind(F f, A1 a1, A2 a2)&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;{&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; //...&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;}&lt;br /&gt; ......&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;br /&gt; &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;但是随之而来的就是问题：我现在把第一个参数（函数指针）类型笼统成了一个&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; F &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;，我如何知道它的返回类型、参数类型和对象类型？好在这个问题可解，其技法在&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; boost &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;里面还很常见，那就是&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; traits &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;：&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;br /&gt; &lt;span style="color: #333399;"&gt;template &amp;lt;typename T&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;struct result_of&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;{};&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&amp;nbsp;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;template &amp;lt;typename R, typename T&amp;gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;struct result_of&amp;lt;R (T::*)()&amp;gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;{&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; typedef R type;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;};&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&amp;nbsp;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;template &amp;lt;typename R, typename T, typename A1&amp;gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;struct result_of&amp;lt;R (T::*)(A1)&amp;gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;{&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; typedef R type;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;};&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&amp;nbsp;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;template &amp;lt;typename R, typename T, typename A1, typename A2&amp;gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;struct result_of&amp;lt;R (T::*)(A1, A2)&amp;gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;{&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; typedef R type;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;};&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;&lt;br /&gt; ......&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;br /&gt; &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;它无非利用&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; C++ &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;模板元编程最常用的偏特化来&amp;#8220;抽取&amp;#8221;函数指针的类型内容，我们甚至无需自己写，&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;boost &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;已经提供好了相应的工具，但是上面的这个&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; result_of &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;也还算清晰好用，在这个例子里面，我们就用它。&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;br /&gt; &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;在这个方向上，思路已经比较开阔了，现在从另一个方向：&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;simple_binder &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;入手来想一想。&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;simple_binder &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;应该长成什么样子呢？由于&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; function_traits &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;可以帮我们得到函数返回类型，我们可以肯定&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; simple_binder &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;在构造的时候已经知道返回类型了，那么它应该是这样吗？&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;br /&gt; &lt;span style="color: #333399;"&gt;template &amp;lt;typename R/*&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family: 宋体; color: #333399;"&gt;返回值的类型&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;*/, typename F, typename A1&amp;gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;class simple_binder&lt;br /&gt; &lt;br /&gt; template &amp;lt;typename R, typename F, typename A1, typename A2&amp;gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;class simple_binder&lt;br /&gt; &lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;如果你的想法是这样，恭喜你，一出门你就撞了南墙：&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;class &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;不是&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; function &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;，除非你偏特化，它是不允许有多个模板参数&amp;#8220;重载&amp;#8221;的！但是很显然，这些&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; simple_binder &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;之间，谁也不是谁的偏特化。那么是不是可以利用类似&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; TypeList &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;的技术，用默认模板参数提供变相的可变参数数量模板：&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;br /&gt; &lt;span style="color: #333399;"&gt;template &amp;lt;typename R, typename F, typename A1, typename A2 = placeholder&amp;lt;0&amp;gt;, typename A3 = placeholder&amp;lt;0&amp;gt; /*...*/ &amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;class simple_binder&lt;br /&gt; ......&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;br /&gt; &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;好，这下子&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; simple_bind &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;的定义算是完整了：&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;br /&gt; &lt;span style="color: #333399;"&gt;template &amp;lt;typename F, typename A1&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;simple_binder&amp;lt;typename result_of&amp;lt;F&amp;gt;::type, F, A1&amp;gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;simple_bind(F f, const A1&amp;amp; arg1)&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;{&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;//...&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;}&lt;br /&gt; &lt;br /&gt; template &amp;lt;typename F, typename A1, typename A2&amp;gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;simple_binder&amp;lt;typename result_of&amp;lt;F&amp;gt;::type, F, A1, A2&amp;gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;simple_bind(F f, const A1&amp;amp; arg1, const A2&amp;amp; arg2)&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;{&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; //...&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;}&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;br /&gt; &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;在这个基础上，提供&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; simple_binder &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;的构造函数也是举手之劳，&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;br /&gt; &lt;span style="color: #333399;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; explicit simple_binder(F f, const A1&amp;amp; a1)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; : f_(f)&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; , a1_(a1)&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {}&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; explicit simple_binder(F f, const A1&amp;amp; a1, const A2&amp;amp; a2)&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; : f_(f)&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; , a1_(a1)&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; , a2_(a2)&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {}&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;br /&gt; &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;其中的&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; f_, a1_, a2_ &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;都是&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; simple_binder &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;的成员。&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;simple_bind &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;仍然只是简单的构造一个&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; simple_binder &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;：&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;br /&gt; &lt;span style="color: #333399;"&gt;template &amp;lt;typename F, typename A1&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;simple_binder&amp;lt;typename result_of&amp;lt;F&amp;gt;::type, F, A1&amp;gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;simple_bind(F f, const A1&amp;amp; arg1)&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;{&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return simple_binder&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; typename result_of&amp;lt;F&amp;gt;::type, &lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; F, &lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; A1&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; (f, arg1);&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;}&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&amp;nbsp;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;template &amp;lt;typename F, typename A1, typename A2&amp;gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;simple_binder&amp;lt;typename result_of&amp;lt;F&amp;gt;::type, F, A1, A2&amp;gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;simple_bind(F f, const A1&amp;amp; arg1, const A2&amp;amp; arg2)&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;{&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return simple_binder&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; typename result_of&amp;lt;F&amp;gt;::type, &lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; F, &lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; A1, &lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; A2&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; (f, arg1, arg2);&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;}&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;br /&gt; &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;至于真正的运算，就留给&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; simple_binder &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;和它的助手们去做。我们仍然从最简单的情况开始，研究一下调用时没有参数是什么样，例如这样的调用：&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;br /&gt; simple_bind(&amp;amp;Person::Name, person)()&lt;br /&gt; &lt;br /&gt; &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;这个调用的参数在&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; simple_bind &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;的时候已经确定，而在&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; simple_binder &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;那里只是简单调用一个&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;0&lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;参数的&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; operator()&lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;，也就是：&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;span style="color: #333399;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; R operator()()&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //...&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt; &lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;即便是这个东西，它代表的意义也不单纯，实际上，在有两个&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; placeholder &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;的场合，它代表了两种情况：&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;br /&gt; 1. &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;类似&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; &lt;span&gt;simple_bind(&amp;amp;Person::Name, person)()&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;，函数实际上没有参数&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; 2. &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;类似&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; simple_bind(&amp;amp;Person::SetName, person, &amp;#8220;Joy&amp;#8221;)(), &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;函数其实有一个参数&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;br /&gt; &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;我们有没有足够的信息来确定是那种情况呢？有，答案就在&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; simple_binder &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;的模板参数&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; A1, A2 &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;中。如果&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; A2 &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;是&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; placeholder&amp;lt;0&amp;gt; &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;，那么就是第一种情况，否则就是第二种情况。为了能在这两种情况之间做出决策，必须加上一个助手，我们称之为&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; eval &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;：&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;br /&gt; &lt;span style="color: #333399;"&gt;template &amp;lt;typename R, typename F, typename A1, typename A2&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;R eval(F f, A1 a1, A2 a2)&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;{&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return (a1.*f)(a2);&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;}&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&amp;nbsp;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;template &amp;lt;typename R, typename F, typename A1&amp;gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;R eval(F f, A1 a1, placeholder&amp;lt;0&amp;gt;)&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;{&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return (a1.*f)();&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;}&lt;br /&gt; &lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;于是乎&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;0&lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;参数的&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; operator() &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;就成了&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;br /&gt; &lt;span style="color: #333399;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; R operator()()&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return eval&amp;lt;R&amp;gt;(f_, a1_, a2_);&lt;/span&gt;&lt;/p&gt;  &lt;span style="font-family: &amp;quot;Courier New&amp;quot;; color: #333399;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt; &lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;参数&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; a2_ &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;会帮助我们把调用分派到两个&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; eval &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;中的一个，从而完成调用决策。&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;br /&gt; &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;现在来考虑&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; 1 &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;个参数的&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; operator() &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;，它就复杂一些了：&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;br /&gt; 1. &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;类似&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; &lt;span&gt;bind(&amp;amp;Person::Name, _1)(person) &lt;/span&gt;&lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;，函数其实没有参数&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; 2. &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;类似&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; &lt;span&gt;bind(&amp;amp;Person::SetName, _1, "Joy")(person)&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;，函数其实有&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;1&lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;个参数，&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;_1 &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;代表第一个&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; 3. &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;类似&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; &lt;span&gt;bind(&amp;amp;Person::SetName, person, _1)("Joy")&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;，函数其实有&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;1&lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;个参数，&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;_1 &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;代表第二个&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;br /&gt; &lt;/span&gt;&lt;strong&gt;&lt;span style="font-family: 宋体;"&gt;停！！！&lt;/span&gt;&lt;/strong&gt;&lt;span style="font-family: 宋体;"&gt;看来在这个方向上鸣金收兵的时候到了。回顾一下这个设计：&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;通过提供&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; generic &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;的&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; simple_bind &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;界面以及&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; result_of &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;，我们简化了&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; simple_bind &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;；又通过&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; eval &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;，我们让&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; simple_binder &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;变得单纯起来，然而现在&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; eval &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;的复杂性开始膨胀，大有脱离我们控制的趋势。原因在哪里？&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;br /&gt; &lt;/span&gt;&lt;strong&gt;&lt;span style="font-family: 宋体;"&gt;参数的复杂性。&lt;/span&gt;&lt;/strong&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt; &lt;br /&gt; &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;作为一个系统，我们的这个东西其实接受两组参数，一组是由&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; simple_bind &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;接受的，混杂了&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; placeholder &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;和实际参数；另一组是由&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; simple_binder &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;的&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; operator() &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;接受的，全部都是实际参数，但是其应用的顺序需要根据&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt; placeholder &lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;的类型来决定。了解了这个复杂性的根源，我们的任务再次变得清晰起来：提供一个方法，以统一的方式来处理参数，降低复杂性。&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/adylee/aggbug/2068322.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/adylee/archive/2011/06/02/2068322.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/adylee/archive/2011/06/02/2067758.html</id><title type="text">[转]boost.bind 如何 bind</title><summary type="text">Boost.bind 好用么？当然好用，而且它也确定进入下一代的 C++ 标准了，也早就进了 TR1 了。回顾一下，它允许我们干这个：#include &lt;algorithm&gt;#include &lt;iostream&gt;#include &lt;string&gt;#include &lt;vector&gt;#include &lt;boost/bind.hpp&gt;using namespace std;using namespace boost;struct Person{ Person(const string&amp; name) : name_(name) {} </summary><published>2011-06-02T02:54:00Z</published><updated>2011-06-02T02:54:00Z</updated><author><name>Ady Lee</name><uri>http://www.cnblogs.com/adylee/</uri></author><link rel="alternate" href="http://www.cnblogs.com/adylee/archive/2011/06/02/2067758.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/adylee/archive/2011/06/02/2067758.html"/><content type="html">&lt;div&gt;&lt;p align="left"&gt;&lt;span style="font-family: Arial"&gt;Boost.bind &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;好用么？当然好用，而且它也确定进入下一代的&lt;/span&gt;&lt;span style="font-family: Arial"&gt; C++ &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;标准了，也早就进了&lt;/span&gt;&lt;span style="font-family: Arial"&gt; TR1 &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;了。回顾一下，它允许我们干这个：&lt;/span&gt;&lt;span style="font-family: Arial"&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #333399"&gt;#include &amp;lt;algorithm&amp;gt;&lt;br /&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;#include &amp;lt;string&amp;gt;&lt;br /&gt;#include &amp;lt;vector&amp;gt;&lt;br /&gt;#include &amp;lt;boost/bind.hpp&amp;gt;&lt;br /&gt;&lt;br /&gt;using namespace std;&lt;br /&gt;using namespace boost;&lt;br /&gt;&lt;br /&gt;struct Person&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Person(const string&amp;amp; name)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; : name_(name)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {}&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; string Name()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return name_;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; string name_;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; typedef vector&amp;lt;Person&amp;gt; PersonList;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; PersonList personList;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; personList.push_back(Person("Ralph"));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; personList.push_back(Person("Joy"));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; personList.push_back(Person("Martin"));&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; PersonList::iterator iter = &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; find_if(personList.begin(), personList.end(),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; bind(&amp;amp;Person::Name, _1) == "Ralph");&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; cout &amp;lt;&amp;lt; (iter == personList.end() ? "Not found." &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; : iter-&amp;gt;Name().append(" found."))&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&amp;lt; endl;&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: 宋体"&gt;如果没有它我们怎么办呢？恕我鲁钝，我还没办法用&lt;/span&gt;&lt;span style="font-family: Arial"&gt; bind1st, bind2nd &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;之类办到同样的事，恐怕你也只有写一个完全没营养的&lt;/span&gt;&lt;span style="font-family: Arial"&gt; predicate &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;来达到目的了。&lt;/span&gt;&lt;span style="font-family: Arial"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: 宋体"&gt;当然，用不了几次，你就会问（或者可能多数人是在第一次看到的时候就会问）：它是怎么办到的？其实还不如问，如果换了你会怎么做？我们降低条件，想象自己&lt;/span&gt; &lt;span style="font-family: 宋体"&gt;是&lt;/span&gt;&lt;span style="font-family: Arial"&gt; bind &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;的作者，在开始的时候舍弃一切细节，只要实现类似&lt;/span&gt;&lt;span style="font-family: Arial"&gt; bind1st &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;或者&lt;/span&gt;&lt;span style="font-family: Arial"&gt; mem_fun &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;的功能，该怎么做？我们把这个&lt;/span&gt;&lt;span style="font-family: Arial"&gt; bind &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;叫做&lt;/span&gt;&lt;span style="font-family: Arial"&gt; simple_bind &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;。&lt;/span&gt;&lt;span style="font-family: Arial"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: Arial"&gt;STL&lt;/span&gt; &lt;span style="font-family: 宋体"&gt;的&lt;/span&gt;&lt;span style="font-family: Arial"&gt; bind1st &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;能给一点启示：它接受两个参数，返回一个&lt;/span&gt;&lt;span style="font-family: Arial"&gt; functor &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;，毫无疑问&lt;/span&gt;&lt;span style="font-family: Arial"&gt; simple_bind &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;也得这样干，我们把它返回的&lt;/span&gt;&lt;span style="font-family: Arial"&gt; functor &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;类型叫做&lt;/span&gt;&lt;span style="font-family: Arial"&gt; simple_binder&lt;/span&gt;&lt;span style="font-family: 宋体"&gt;：&lt;/span&gt;&lt;span style="font-family: Arial"&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #333399"&gt;template &amp;lt;typename R, typename T&amp;gt;&lt;br /&gt;class simple_binder&lt;br /&gt;{&lt;br /&gt;public:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; explicit simple_binder(R (T::*pfn)())&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; : pfn_(pfn)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; R operator()(T&amp;amp; t)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return t.*pfn_();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;private:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; R (T::*pfn_)();&lt;br /&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: 宋体"&gt;这个东西跟&lt;/span&gt;&lt;span style="font-family: Arial"&gt; mem_fun_ref_t &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;可以相比，因为毕竟，算法是不变的，无论我们在外面玩什么花样，提供给算法的&lt;/span&gt;&lt;span style="font-family: Arial"&gt; functor &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;类型都必须长成这样。中间的&lt;/span&gt;&lt;span style="font-family: Arial"&gt; R (T::*pfn)() &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;是函数指针定义，的确，&lt;/span&gt;&lt;span style="font-family: Arial"&gt;C++ &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;里面的函数指针定义从来就不可爱，所以才有了&lt;/span&gt;&lt;span style="font-family: Arial"&gt; boost.function ... &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;扯远了。&lt;/span&gt;&lt;span style="font-family: Arial"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: 宋体"&gt;我们知道了&lt;/span&gt;&lt;span style="font-family: Arial"&gt; simple_bind &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;的返回类型，那么参数呢，第一个参数简单，跟上面的&lt;/span&gt;&lt;span style="font-family: Arial"&gt; pfn &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;是一样的，第二个是什么呢？我们先空起来：&lt;/span&gt;&lt;span style="font-family: Arial"&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #333399"&gt;template &amp;lt;typename R, typename T&amp;gt;&lt;br /&gt;simple_binder&amp;lt;R, T&amp;gt;&lt;br /&gt;simple_bind( R (T::*pfn)(), ??? )&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return simple_binder&amp;lt;R, T&amp;gt;(pfn);&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: 宋体"&gt;有没有发现什么？在这里我们压根没用到第二个参数，这就给了我们一个极其简单的定义：&lt;/span&gt;&lt;span style="font-family: Arial"&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #333399"&gt;class placeholder{};&lt;br /&gt;placeholder _1;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: 宋体"&gt;那么现在程序好像是完整了，我们可以这么用：&lt;/span&gt;&lt;span style="font-family: Arial"&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #333399"&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;#include &amp;lt;string&amp;gt;&lt;br /&gt;&lt;br /&gt;using namespace std;&lt;br /&gt;&lt;br /&gt;struct Person&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Person(const string&amp;amp; name)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; : name_(name)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; string Name()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return name_;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; string name_;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;template &amp;lt;typename R, typename T&amp;gt;&lt;br /&gt;class simple_binder&lt;br /&gt;{&lt;br /&gt;public:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; explicit simple_binder(R (T::*pfn)())&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; : pfn_(pfn)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; R operator()(T&amp;amp; t)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;strong&gt;return (t.*pfn_)();&lt;/strong&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;private:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; R (T::*pfn_)();&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;class placeholder{};&lt;br /&gt;placeholder _1;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;template &amp;lt;typename R, typename T&amp;gt;&lt;br /&gt;simple_binder&amp;lt;R, T&amp;gt;&lt;br /&gt;simple_bind( R (T::*pfn)(), placeholder&amp;amp;)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;strong&gt;return simple_binder&amp;lt;R, T&amp;gt;(pfn);&lt;/strong&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Person person("Ralph");&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; cout &amp;lt;&amp;lt; simple_bind(&amp;amp;Person::Name, _1)(person) &amp;lt;&amp;lt; endl;&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: 宋体"&gt;输出是&lt;/span&gt;&lt;span style="font-family: Arial"&gt; &lt;span style="color: gray"&gt;Ralph&lt;/span&gt; &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;，跟直接调用一样！我们的&lt;/span&gt;&lt;span style="font-family: Arial"&gt; simple_bind &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;起作用了！&lt;/span&gt;&lt;span style="font-family: Arial"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: 宋体"&gt;好了，现在让我们再向前一步，如果&lt;/span&gt;&lt;span style="font-family: Arial"&gt; Person &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;加了一个函数&lt;/span&gt;&lt;span style="font-family: Arial"&gt; SetName:&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #333399"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; void SetName(string name)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; name_ = name;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: 宋体"&gt;它有一个参数，而我们希望调用的形式类似于&lt;/span&gt;&lt;span style="font-family: Arial"&gt; &lt;strong&gt;&lt;span style="color: #333399"&gt;simple_bind(&amp;amp;Person::SetName, string("Joy"), _1)&lt;/span&gt;&lt;/strong&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="font-family: 宋体"&gt;我们怎么修改&lt;/span&gt;&lt;span style="font-family: Arial"&gt; simple_bind &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;呢？&lt;/span&gt;&lt;span style="font-family: Arial"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: 宋体"&gt;首先还是从&lt;/span&gt;&lt;span style="font-family: Arial"&gt; simple_binder &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;入手，由于调用方法不变，我们所要做的只是在&lt;/span&gt;&lt;span style="font-family: Arial"&gt; simple_binder &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;里面保存参数，没错，就跟&lt;/span&gt;&lt;span style="font-family: Arial"&gt; binder1st &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;一样：&lt;/span&gt;&lt;span style="font-family: Arial"&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #333399"&gt;template &amp;lt;typename R, typename T, typename Arg&amp;gt;&lt;br /&gt;class simple_binder&lt;br /&gt;{&lt;br /&gt;public:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; explicit simple_binder(R (T::*pfn)(Arg), const Arg&amp;amp; arg)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; : pfn_(pfn)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; , arg_(arg)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; R operator()(T&amp;amp; t)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return (t.*pfn_)(arg_);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;private:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; R (T::*pfn_)(Arg);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Arg arg_;&lt;br /&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: 宋体"&gt;接下来的就顺理成章了，&lt;/span&gt;&lt;span style="font-family: Arial"&gt;simple_bind &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;把&lt;/span&gt;&lt;span style="font-family: Arial"&gt; arg &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;传递给&lt;/span&gt;&lt;span style="font-family: Arial"&gt; simple_binder &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;，而&lt;/span&gt;&lt;span style="font-family: Arial"&gt; placeholder &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;甚至不需要修改，我们甚至可以把这个&lt;/span&gt;&lt;span style="font-family: Arial"&gt; simple_bind &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;直接喂给&lt;/span&gt; &lt;span style="font-family: Arial"&gt;STL&lt;/span&gt; &lt;span style="font-family: 宋体"&gt;算法：&lt;/span&gt;&lt;span style="font-family: Arial"&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #333399"&gt;#include &amp;lt;algorithm&amp;gt;&lt;br /&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;#include &amp;lt;string&amp;gt;&lt;br /&gt;#include &amp;lt;vector&amp;gt;&lt;br /&gt;&lt;br /&gt;using namespace std;&lt;br /&gt;&lt;br /&gt;struct Person&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Person(const string&amp;amp; name)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; : name_(name)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; string Name()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return name_;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; void SetName(string name)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; name_ = name;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; string name_;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;template &amp;lt;typename R, typename T, typename Arg&amp;gt;&lt;br /&gt;class simple_binder&lt;br /&gt;{&lt;br /&gt;public:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; explicit simple_binder(R (T::*pfn)(Arg), const Arg&amp;amp; arg)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; : pfn_(pfn)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; , arg_(arg)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; R operator()(T&amp;amp; t)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return (t.*pfn_)(arg_);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;private:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; R (T::*pfn_)(Arg);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Arg arg_;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;class placeholder{};&lt;br /&gt;placeholder _1;&lt;br /&gt;&lt;br /&gt;template &amp;lt;typename R, typename T, typename Arg&amp;gt;&lt;br /&gt;simple_binder&amp;lt;R, T, Arg&amp;gt;&lt;br /&gt;simple_bind( R (T::*pfn)(Arg), const Arg&amp;amp; arg, placeholder&amp;amp;)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return simple_binder&amp;lt;R, T, Arg&amp;gt;(pfn, arg);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; typedef vector&amp;lt;Person&amp;gt; PersonList;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; PersonList personList;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; personList.push_back(Person("Ralph"));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; personList.push_back(Person("Joy"));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; personList.push_back(Person("Martin"));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; for_each(personList.begin(), personList.end(), &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; simple_bind(&amp;amp;Person::SetName, string("Joy"), _1));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; cout &amp;lt;&amp;lt; personList[0].Name() &amp;lt;&amp;lt; endl&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&amp;lt; personList[1].Name() &amp;lt;&amp;lt; endl&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&amp;lt; personList[2].Name() &amp;lt;&amp;lt; endl;&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: 宋体"&gt;输出是三个&lt;/span&gt;&lt;span style="font-family: Arial"&gt; &lt;span style="color: gray"&gt;Joy&lt;/span&gt; &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;。&lt;/span&gt;&lt;span style="font-family: Arial"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: 宋体"&gt;现在看起来，我们的&lt;/span&gt;&lt;span style="font-family: Arial"&gt; simple_binder &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;稍微有点样子了，但是&lt;/span&gt;&lt;span style="font-family: Arial"&gt; boost.bind &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;允许&lt;/span&gt;&lt;span style="font-family: Arial"&gt; placeholder &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;被放在任何一个位置，而&lt;/span&gt;&lt;span style="font-family: Arial"&gt; simple_binder &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;不允许，但是这个简单，我们有重载：&lt;/span&gt;&lt;/p&gt; &lt;p align="left"&gt;&lt;span style="color: #333399; font-family: Arial"&gt;template &amp;lt;typename R, typename T, typename Arg&amp;gt;&lt;br /&gt;simple_binder&amp;lt;R, T, Arg&amp;gt;&lt;br /&gt;simple_bind( R (T::*pfn)(Arg), const placeholder&amp;amp;, const Arg&amp;amp; arg)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return simple_binder&amp;lt;R, T, Arg&amp;gt;(pfn, arg);&lt;br /&gt;}&lt;/span&gt; &lt;/p&gt; &lt;p align="left"&gt;&lt;span style="font-family: 宋体"&gt;加上这个，&lt;/span&gt;&lt;span style="font-family: Arial"&gt;_1 &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;就可以被随便放在第一个或者第二个位置，例如：&lt;/span&gt;&lt;/p&gt; &lt;p align="left"&gt;&lt;span style="color: #333399; font-family: Arial"&gt;int main()&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; typedef vector&amp;lt;Person&amp;gt; PersonList;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; PersonList personList;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; personList.push_back(Person("Ralph"));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; personList.push_back(Person("Joy"));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; personList.push_back(Person("Martin"));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; for_each(personList.begin(), personList.end(), &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; simple_bind(&amp;amp;Person::SetName, string("Joy"), _1));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; for_each(personList.begin(), personList.end(),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; simple_bind(&amp;amp;Person::SetName, _1, string("Ralph")));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; cout &amp;lt;&amp;lt; personList[0].Name() &amp;lt;&amp;lt; endl&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&amp;lt; personList[1].Name() &amp;lt;&amp;lt; endl&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&amp;lt; personList[2].Name() &amp;lt;&amp;lt; endl;&lt;br /&gt;}&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: Arial"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: 宋体"&gt;输出是三个&lt;/span&gt;&lt;span style="font-family: Arial"&gt; &lt;span style="color: gray"&gt;Ralph&lt;/span&gt; &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;。提醒一下，&lt;/span&gt;&lt;span style="font-family: Arial"&gt;boost.bind &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;当然不是用这个办法，要不然还不用等到参数数量到&lt;/span&gt;&lt;span style="font-family: Arial"&gt;10&lt;/span&gt;&lt;span style="font-family: 宋体"&gt;个，到了&lt;/span&gt;&lt;span style="font-family: Arial"&gt;3&lt;/span&gt;&lt;span style="font-family: 宋体"&gt;个我们就要累死。&lt;/span&gt;&lt;span style="font-family: Arial"&gt;simple_bind &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;的目的只是在于探索，用最容易理解的方式达成目的，如果说&lt;/span&gt;&lt;span style="font-family: Arial"&gt; boost &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;是一座拆除了脚手架、精雕细琢的圣殿，&lt;/span&gt;&lt;span style="font-family: Arial"&gt;simple_bind &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;就是尝试把脚手架再搭起来。&lt;/span&gt;&lt;/p&gt; &lt;p align="left"&gt;&lt;span style="font-family: 宋体"&gt;回顾一下，现在我们已经能比较好地解决一个参数的成员函数调用了，现在看看两个参数。我们从目的入手，希望达到的效果是这样：&lt;/span&gt;&lt;/p&gt; &lt;p align="left"&gt;&lt;span style="color: #333399; font-family: Arial"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Person person("Ralph");&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; simple_bind(&amp;amp;Person::SetName, _1, _2)(person, string("Martin"));&lt;/span&gt;&lt;/p&gt; &lt;p align="left"&gt;&lt;span style="font-family: 宋体"&gt;首先，这里有了一个新的符号&lt;/span&gt;&lt;span style="font-family: Arial"&gt; _2 &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;，这很简单&lt;/span&gt;&lt;/p&gt; &lt;p align="left"&gt;&lt;span style="color: #333399; font-family: Arial"&gt;placeholder _2;&lt;/span&gt;&lt;/p&gt; &lt;p align="left"&gt;&lt;span style="font-family: 宋体"&gt;然后&lt;/span&gt;&lt;span style="font-family: Arial"&gt; simple_bind &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;也顺利成章的又增加了一个重载：&lt;/span&gt;&lt;/p&gt; &lt;p align="left"&gt;&lt;span style="color: #333399; font-family: Arial"&gt;template &amp;lt;typename R, typename T, typename Arg&amp;gt;&lt;br /&gt;simple_binder&amp;lt;R, T, Arg&amp;gt;&lt;br /&gt;simple_bind( R (T::*pfn)(Arg), const placeholder&amp;amp;, const placeholder&amp;amp;)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return simple_binder&amp;lt;R, T, Arg&amp;gt;(pfn);&lt;br /&gt;}&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: Arial"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: 宋体"&gt;注意，这个&lt;/span&gt;&lt;span style="font-family: Arial"&gt; simple_binder &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;构造函数只有一个参数，而它还没写出来，我们加上一个：&lt;/span&gt;&lt;/p&gt; &lt;p align="left"&gt;&lt;span style="color: #333399; font-family: Arial"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // new simple_binder ctor: 1 argument&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; explicit simple_binder(R (T::*pfn)(Arg))&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; : pfn_(pfn)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {}&amp;nbsp;&lt;/span&gt;&lt;/p&gt; &lt;p align="left"&gt;&lt;span style="font-family: 宋体"&gt;在这种情况下，两个参数都是由调用者直接提供给&lt;/span&gt;&lt;span style="font-family: Arial"&gt; simple_binder &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;的，这就意味着我们还要重载一次&lt;/span&gt;&lt;span style="font-family: Arial"&gt; simple_binder::operator() &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;：&lt;/span&gt;&lt;/p&gt; &lt;p align="left"&gt;&lt;span style="color: #333399; font-family: Arial"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; R operator()(T&amp;amp; t, const Arg&amp;amp; arg)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return (t.*pfn_)(arg);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/p&gt; &lt;p align="left"&gt;&lt;span style="font-family: 宋体"&gt;好了，这下子都解决了，完整程序如下：&lt;/span&gt;&lt;/p&gt; &lt;p align="left"&gt;&lt;span style="color: #333399; font-family: Arial"&gt;#include &amp;lt;algorithm&amp;gt;&lt;br /&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;#include &amp;lt;string&amp;gt;&lt;br /&gt;#include &amp;lt;vector&amp;gt;&lt;/span&gt;&lt;/p&gt; &lt;p align="left"&gt;&lt;span style="color: #333399; font-family: Arial"&gt;using namespace std;&lt;/span&gt;&lt;/p&gt; &lt;p align="left"&gt;&lt;span style="color: #333399; font-family: Arial"&gt;struct Person&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Person(const string&amp;amp; name)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; : name_(name)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; string Name()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return name_;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; void SetName(string name)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; name_ = name;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; string name_;&lt;br /&gt;};&lt;/span&gt;&lt;/p&gt; &lt;p align="left"&gt;&lt;span style="color: #333399; font-family: Arial"&gt;template &amp;lt;typename R, typename T, typename Arg&amp;gt;&lt;br /&gt;class simple_binder&lt;br /&gt;{&lt;br /&gt;public:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; explicit simple_binder(R (T::*pfn)(Arg))&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; : pfn_(pfn)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; explicit simple_binder(R (T::*pfn)(Arg), const Arg&amp;amp; arg)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; : pfn_(pfn)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; , arg_(arg)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; R operator()(T&amp;amp; t)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return (t.*pfn_)(arg_);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/span&gt;&lt;/p&gt; &lt;p align="left"&gt;&lt;span style="color: #333399; font-family: Arial"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; R operator()(T&amp;amp; t, const Arg&amp;amp; arg)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return (t.*pfn_)(arg);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;private:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; R (T::*pfn_)(Arg);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Arg arg_;&lt;br /&gt;};&lt;/span&gt;&lt;/p&gt; &lt;p align="left"&gt;&lt;span style="color: #333399; font-family: Arial"&gt;class placeholder{};&lt;br /&gt;placeholder _1, _2;&lt;/span&gt;&lt;/p&gt; &lt;p align="left"&gt;&lt;span style="color: #333399; font-family: Arial"&gt;template &amp;lt;typename R, typename T, typename Arg&amp;gt;&lt;br /&gt;simple_binder&amp;lt;R, T, Arg&amp;gt;&lt;br /&gt;simple_bind( R (T::*pfn)(Arg), const Arg&amp;amp; arg, const placeholder&amp;amp;)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return simple_binder&amp;lt;R, T, Arg&amp;gt;(pfn, arg);&lt;br /&gt;}&lt;/span&gt;&lt;/p&gt; &lt;p align="left"&gt;&lt;span style="color: #333399; font-family: Arial"&gt;template &amp;lt;typename R, typename T, typename Arg&amp;gt;&lt;br /&gt;simple_binder&amp;lt;R, T, Arg&amp;gt;&lt;br /&gt;simple_bind( R (T::*pfn)(Arg), const placeholder&amp;amp;, const Arg&amp;amp; arg)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return simple_binder&amp;lt;R, T, Arg&amp;gt;(pfn, arg);&lt;br /&gt;}&lt;/span&gt;&lt;/p&gt; &lt;p align="left"&gt;&lt;span style="color: #333399; font-family: Arial"&gt;template &amp;lt;typename R, typename T, typename Arg&amp;gt;&lt;br /&gt;simple_binder&amp;lt;R, T, Arg&amp;gt;&lt;br /&gt;simple_bind( R (T::*pfn)(Arg), const placeholder&amp;amp;, const placeholder&amp;amp;)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return simple_binder&amp;lt;R, T, Arg&amp;gt;(pfn);&lt;br /&gt;}&lt;/span&gt;&lt;/p&gt; &lt;p align="left"&gt;&lt;span style="color: #333399; font-family: Arial"&gt;int main()&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; typedef vector&amp;lt;Person&amp;gt; PersonList;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; PersonList personList;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; personList.push_back(Person("Ralph"));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; personList.push_back(Person("Joy"));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; personList.push_back(Person("Martin"));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; for_each(personList.begin(), personList.end(), &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; simple_bind(&amp;amp;Person::SetName, string("Joy"), _1));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; for_each(personList.begin(), personList.end(),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; simple_bind(&amp;amp;Person::SetName, _1, string("Ralph")));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Person person("Ralph");&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; simple_bind(&amp;amp;Person::SetName, _1, _2)(person, string("Martin"));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; cout &amp;lt;&amp;lt; personList[0].Name() &amp;lt;&amp;lt; endl&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&amp;lt; personList[1].Name() &amp;lt;&amp;lt; endl&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&amp;lt; personList[2].Name() &amp;lt;&amp;lt; endl;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; cout &amp;lt;&amp;lt; person.Name() &amp;lt;&amp;lt; endl;&lt;br /&gt;}&lt;/span&gt;&lt;/p&gt; &lt;p align="left"&gt;&lt;span style="font-family: 宋体"&gt;输出是：&lt;/span&gt;&lt;/p&gt; &lt;p align="left"&gt;&lt;span style="color: gray; font-family: Arial"&gt;Ralph&lt;br /&gt;Ralph&lt;br /&gt;Ralph&lt;br /&gt;Martin&lt;/span&gt;&lt;/p&gt; &lt;p align="left"&gt;&lt;span style="font-family: 宋体"&gt;虽然实现丑陋了点，但是达到目的了，不是么？好了，现在新的问题来了，我们还希望可以这样：&lt;/span&gt;&lt;/p&gt; &lt;p align="left"&gt;&lt;span style="color: #333399; font-family: Arial"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; simple_bind(&amp;amp;Person::SetName, _2, _1)(string("Joy"), person));&lt;/span&gt;&lt;/p&gt; &lt;p align="left"&gt;&lt;span style="font-family: 宋体"&gt;其实从这里可以看出来，在前面的实现中，&lt;/span&gt;&lt;span style="font-family: Arial"&gt;placeholder &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;没有发挥任何作用，是真正的&lt;/span&gt;&lt;span style="font-family: Arial"&gt; placeholder &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;，然而在这里不同，我们至少希望&lt;/span&gt;&lt;span style="font-family: Arial"&gt; placeholder &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;能够携带某些编译期信息，以便让我们能在调用决策中选择相应的参数，换句话说，我们希望&lt;/span&gt;&lt;span style="font-family: Arial"&gt; placeholder _1 &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;和&lt;/span&gt;&lt;span style="font-family: Arial"&gt; _2 &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;除了名字不同，还能让编译器看起来有所区别，当然最简单的想法是：&lt;/span&gt;&lt;/p&gt; &lt;p align="left"&gt;&lt;span style="color: #333399; font-family: Arial"&gt;class placeholder1{};&lt;br /&gt;class placeholder2{};&lt;br /&gt;placeholder1 _1;&lt;br /&gt;placeholder2 _2;&lt;/span&gt;&lt;/p&gt; &lt;p align="left"&gt;&lt;span style="font-family: 宋体"&gt;然而模仿&lt;/span&gt; &lt;span style="font-family: Arial"&gt;MCD&lt;/span&gt; &lt;span style="font-family: 宋体"&gt;的&lt;/span&gt;&lt;span style="font-family: Arial"&gt; IntToType &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;技术，这样是不是更优雅呢：&lt;/span&gt;&lt;/p&gt; &lt;p align="left"&gt;&lt;span style="color: #333399; font-family: Arial"&gt;template &amp;lt;int I&amp;gt;&lt;br /&gt;class placeholder{};&lt;br /&gt;placeholder&amp;lt;1&amp;gt; _1;&lt;br /&gt;placeholder&amp;lt;2&amp;gt; _2;&lt;/span&gt;&lt;/p&gt; &lt;p align="left"&gt;&lt;span style="font-family: Arial"&gt;boost.bind &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;里面就是这么干的。有了这个，就可以依照&lt;/span&gt;&lt;span style="font-family: Arial"&gt; placeholder &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;顺序来重载：&lt;/span&gt;&lt;/p&gt; &lt;p align="left"&gt;&lt;span style="color: #333399; font-family: Arial"&gt;template &amp;lt;typename R, typename T, typename Arg&amp;gt;&lt;br /&gt;simple_binder&amp;lt;R, T, Arg&amp;gt;&lt;br /&gt;simple_bind( R (T::*pfn)(Arg), const placeholder&amp;lt;1&amp;gt;&amp;amp;, const placeholder&amp;lt;2&amp;gt;&amp;amp;)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return simple_binder&amp;lt;R, T, Arg&amp;gt;(pfn);&lt;br /&gt;}&lt;/span&gt;&lt;/p&gt; &lt;p align="left"&gt;&lt;span style="color: #333399; font-family: Arial"&gt;template &amp;lt;typename R, typename T, typename Arg&amp;gt;&lt;br /&gt;simple_binder&amp;lt;R, T, Arg&amp;gt;&lt;br /&gt;simple_bind( R (T::*pfn)(Arg), const placeholder&amp;lt;2&amp;gt;&amp;amp;, const placeholder&amp;lt;1&amp;gt;&amp;amp;)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // &lt;/span&gt;&lt;span style="color: #333399; font-family: 宋体"&gt;返回什么呢？&lt;/span&gt;&lt;span style="color: #333399; font-family: Arial"&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: Arial"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: 宋体"&gt;返回什么呢？我们可以定义一个&lt;/span&gt;&lt;span style="font-family: Arial"&gt; simple_binder2 &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;，它在&lt;/span&gt;&lt;span style="font-family: Arial"&gt; operator() &lt;/span&gt;&lt;span style="font-family: 宋体"&gt;里面会交换其参数的位置，也可以修改&lt;/span&gt;&lt;span style="font-family: Arial"&gt; simple_binder&lt;/span&gt;&lt;span style="font-family: 宋体"&gt;，让它根据某些标志来干这件事&lt;/span&gt;&lt;span style="font-family: Arial"&gt;&amp;#8230;&amp;#8230;&lt;/span&gt;&lt;/p&gt; &lt;p align="left"&gt;&lt;strong&gt;&lt;span style="font-family: 宋体"&gt;我们还是就此打住吧！&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt; &lt;p align="left"&gt;&lt;span style="font-family: 宋体"&gt;不用我说你也看得出来，这种&lt;/span&gt;&lt;span style="font-family: Arial"&gt;&amp;#8220;&lt;/span&gt;&lt;span style="font-family: 宋体"&gt;暴力法&lt;/span&gt;&lt;span style="font-family: Arial"&gt;&amp;#8221;&lt;/span&gt;&lt;span style="font-family: 宋体"&gt;很   快就会让代码规模和程序复杂度膨胀到无法收拾的地步，是时候检讨我们的设计了。我们原先的设计其实是从最简单的情况出发，在需求增多的时候，我们用蛮力加 以扩展，然而当规模进一步扩大，设计本身的局限就开始显现出来，现在应该从原先的设计中提取抽象，考虑更加灵活的设计了。&lt;/span&gt;&lt;/p&gt; &lt;span style="font-family: 宋体"&gt;（待续&lt;/span&gt;&lt;span style="font-family: Arial"&gt;...&lt;/span&gt;&lt;span style="font-family: 宋体"&gt;）&lt;/span&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/adylee/aggbug/2067758.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/adylee/archive/2011/06/02/2067758.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/adylee/archive/2011/06/01/2067142.html</id><title type="text">[转]boost bind使用指南</title><summary type="text">bind - boost 头文件: boost/bind.hpp bind 是一组重载的函数模板.用来向一个函数(或函数对象)绑定某些参数. bind的返回值是一个函数对象. 它的源文件太长了. 看不下去. 这里只记下它的用法: 9.1 对于普通函数 假如有函数 fun() 如下: void fun(int x, int y) {cout &lt;&lt; x &lt;&lt; ", " &lt;&lt; y &lt;&lt; endl;}现在我们看看怎么用bind 向其绑定参数. 对于像 fun 这样的普通函数. 若fun 有n个参数. 则 bind 需要 n+1 个参数</summary><published>2011-06-01T08:35:00Z</published><updated>2011-06-01T08:35:00Z</updated><author><name>Ady Lee</name><uri>http://www.cnblogs.com/adylee/</uri></author><link rel="alternate" href="http://www.cnblogs.com/adylee/archive/2011/06/01/2067142.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/adylee/archive/2011/06/01/2067142.html"/><content type="html">&lt;div&gt;&lt;p&gt;&lt;span style="font-size: medium;"&gt;bind - boost&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style="font-size: medium;"&gt;头文件: boost/bind.hpp&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style="font-size: medium;"&gt;&lt;span style="color: #0000ff;"&gt;bind&lt;/span&gt; 是一组重载的函数模板.&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: medium;"&gt;用来向一个函数(或函数对象)绑定某些参数. &lt;br /&gt;bind的返回值是一个函数对象. &lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style="font-size: medium;"&gt;它的源文件太长了. 看不下去. 这里只记下它的用法: &lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style="font-size: medium;"&gt;9.1 对于普通函数&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style="font-size: medium;"&gt;假如有函数 fun() 如下: &lt;br /&gt;&amp;nbsp;&lt;span style="color: #ff6600;"&gt;void fun(int x, int y)&lt;/span&gt; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;cout &amp;lt;&amp;lt; x &amp;lt;&amp;lt; ", " &amp;lt;&amp;lt; y &amp;lt;&amp;lt; endl;&lt;br /&gt;&amp;nbsp;}&lt;br /&gt;现在我们看看怎么用bind 向其绑定参数. &lt;br /&gt;&lt;span style="color: #0000ff;"&gt;对于像 fun 这样的普通函数. 若fun 有n个参数. 则 bind 需要 n+1 个参数: 原始函数的地址 以及 n个要绑定的参数.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style="font-size: medium;"&gt;&lt;span style="color: #0000ff;"&gt;第1种用法:&lt;/span&gt; &lt;br /&gt;向原始函数 fun 绑定所有的参数&lt;br /&gt;&amp;nbsp;boost::bind(&amp;amp;fun, 3, 4)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // bind的实参表依次为: 要绑定的函数的地址, 绑定到fun的第一个参数值, 第二个参数值...&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// fun有多少个参数, 这里就要提供多少个.&lt;br /&gt;表示将 3 和 4 作为参数绑定到 fun 函数. &lt;br /&gt;因为绑定了所有的参数. 现在我们调用bind所返回的函数对象:&lt;br /&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="font-size: medium;"&gt;&lt;span style="color: #ff0000;"&gt;boost::bind(&amp;amp;fun, 3, 4)( );&amp;nbsp; //无参数. &lt;br /&gt;&lt;/span&gt;就会输出 3, 4&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style="font-size: medium;"&gt;&lt;span style="color: #0000ff;"&gt;第2种用法:&lt;/span&gt; &lt;br /&gt;向原始函数 fun 绑定一部分参数&lt;br /&gt;&amp;nbsp;boost::bind(&amp;amp;fun, 3, _1)&amp;nbsp;&amp;nbsp;&amp;nbsp; // bind的实参表依次还是: 要绑定的函数的地址, 要绑定到fun的第一个参数值, 然后注意&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// 因为我们不打算向fun绑定第2个参数(即我们希望在调用返回的Functor时再指定这个参数的值)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// 所以这里使用 _1 来占位. 这里的 _1 代表该新函数对象被调用时. 实参表的第1个参数.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// 同理下边还会用到 _2 _3 这样的占位符. &lt;br /&gt;这里只为fun绑定了第一个参数3. 所以在调用bind返回的函数对象时. 需要:&lt;br /&gt;&amp;nbsp;&lt;span style="color: #ff0000;"&gt;boost::bind(&amp;amp;fun, 3, _1)(4);&amp;nbsp; //这个4 会代替 _1 占位符.&lt;/span&gt;&lt;br /&gt;输出 3, 4&lt;br /&gt;同理 boost::bind(&amp;amp;fun, _1, 3)(4); &lt;br /&gt;输出 4, 3&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style="font-size: medium;"&gt;&lt;span style="color: #0000ff;"&gt;第3种用法:&lt;/span&gt;&lt;br /&gt;不向 fun 绑定任何参数&lt;br /&gt;&amp;nbsp;boost::bind(&amp;amp;fun, _1, _2)&amp;nbsp;&amp;nbsp; // _1 _2 都是占位符. 上边已经说过了.&lt;br /&gt;所以它就是 将新函数对象在调用时的实参表的第1个参数和第2个参数 绑定到fun函数.&amp;nbsp; &lt;br /&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="font-size: medium;"&gt;&lt;span style="color: #ff0000;"&gt;boost::bind(&amp;amp;fun, _1, _2)(3, 4);&amp;nbsp;&amp;nbsp;&amp;nbsp; // 3将代替_1占位符, 4将代替_2占位符.&lt;br /&gt;&lt;/span&gt;输出 3, 4&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: medium;"&gt;&lt;span style="color: #ff0000;"&gt;同理 boost::bind(&amp;amp;fun, _2, _1)(3, 4);&amp;nbsp;&amp;nbsp; // 3将代替_1占位符, 4将代替_2占位符.&lt;br /&gt;&lt;/span&gt;会输出 4, 3&amp;nbsp; &lt;br /&gt;同理 boost::bind(&amp;amp;fun, _1, _1)(3); &amp;nbsp;&amp;nbsp;&amp;nbsp; // 3将代替_1占位符&lt;br /&gt;会输出 3, 3&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style="font-size: medium;"&gt;对于普通函数就这些. &lt;span style="color: #0000ff;"&gt;对于函数对象&lt;/span&gt;. 如:&lt;br /&gt;&amp;nbsp;struct Func {&lt;br /&gt;&amp;nbsp;&amp;nbsp;void operator()(int x) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;cout &amp;lt;&amp;lt; x &amp;lt;&amp;lt; endl;&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;} f;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: medium;"&gt;&lt;span style="color: #0000ff;"&gt;绑定的时候可能要指出返回值的类型:&lt;br /&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color: #ff0000;"&gt;boost::bind&amp;lt;&lt;span style="color: #0000ff;"&gt;void&lt;/span&gt;&amp;gt;(f, 3)();&lt;/span&gt;&amp;nbsp; //指出返回值的类型 void&lt;br /&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style="font-size: medium;"&gt;9.2 对于非静态成员函数&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style="font-size: medium;"&gt;假如有:&lt;br /&gt;&amp;nbsp;struct A {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span style="color: #ff6600;"&gt;void func(int x, int y)&lt;/span&gt; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;cout &amp;lt;&amp;lt; x &amp;lt;&amp;lt; "," &amp;lt;&amp;lt; y &amp;lt;&amp;lt; endl;&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;};&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;A a;&amp;nbsp; &lt;br /&gt;&amp;nbsp;A* pa = new A;&amp;nbsp;//指针&lt;br /&gt;&amp;nbsp;boost::shared_ptr&amp;lt;A&amp;gt; ptr_a(pa);&amp;nbsp; //智能指针.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;现在&lt;/span&gt;&lt;span style="font-size: medium;"&gt;&lt;span style="color: #0000ff;"&gt;要向像 A::func 这样的非静态成员函数绑定. &lt;br /&gt;若A::func有n个参数, 则 bind 要有 n+2 个参数: 指向成员函数fun的指针, 绑定到this的对象, n个参数.&lt;br /&gt;&lt;/span&gt;如:&amp;nbsp; &lt;br /&gt;&amp;nbsp;&lt;span style="color: #ff0000;"&gt;boost::bind(&amp;amp;A::func,&lt;span style="color: #0000ff;"&gt; a&lt;/span&gt;, 3, 4)();&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; //输出 3, 4&lt;br /&gt;&amp;nbsp;&lt;span style="color: #ff0000;"&gt;boost::bind(&amp;amp;A::func, &lt;span style="color: #0000ff;"&gt;pa&lt;/span&gt;, 3, 4)();&lt;/span&gt;&amp;nbsp;&amp;nbsp; //输出 3, 4&lt;br /&gt;&amp;nbsp;&lt;span style="color: #ff0000;"&gt;boost::bind(&amp;amp;A::func, &lt;span style="color: #0000ff;"&gt;ptr_a&lt;/span&gt;, 3, 4)();&lt;/span&gt;//输出 3, 4&lt;br /&gt;同样可以用 _1 这样的占位符. 如:&lt;br /&gt;&amp;nbsp;boost::bind(&amp;amp;A::func, _1, 3, 4)(ptr_a);//输出 3, 4&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style="font-size: medium;"&gt;&lt;span style="color: #0000ff;"&gt;可以看出. 不论传递给bind 的第2个参数是 对象. 对象指针. 还是智能指针. bind函数都能够正常工作.&lt;/span&gt; &lt;/span&gt;&lt;/p&gt; &lt;p&gt; &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;span style="font-size: medium;"&gt;9.3 bind嵌套&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style="font-size: medium;"&gt;有个类如下. 记录人的信息:&lt;br /&gt;&amp;nbsp;class Personal_info {&lt;br /&gt;&amp;nbsp;&amp;nbsp;string name_;&lt;br /&gt;&amp;nbsp;&amp;nbsp;int age_;&lt;br /&gt;&amp;nbsp;public:&lt;br /&gt;&amp;nbsp;&amp;nbsp;int get_age();&lt;br /&gt;&amp;nbsp;&amp;nbsp;string name();&lt;br /&gt;&amp;nbsp;};&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style="font-size: medium;"&gt;&amp;nbsp;vector&amp;lt;Personal_info&amp;gt; vec; &lt;br /&gt;&amp;nbsp;...&lt;br /&gt;现在要对 vec 排序. 可以用 bind 函数做一个比较谓词&lt;br /&gt;&amp;nbsp;std::sort(&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;vec.begin(),&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;vec.end(),&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;boost::bind( &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;std::less&amp;lt;int&amp;gt;(),&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;boost::bind(&amp;amp;personal_info::age,_1),&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //_1 占位符是 sort 中调用比较函数时的第一个参数.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;boost::bind(&amp;amp;personal_info::age,_2)));&amp;nbsp;&amp;nbsp; //_2 占位符是 sort 中调用比较函数时的第二个参数.&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;br /&gt;&lt;span style="font-size: medium;"&gt;9.4 函数组合&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style="font-size: medium;"&gt;假如有:&lt;br /&gt;&amp;nbsp;vector&amp;lt;int&amp;gt; ints;&lt;br /&gt;&amp;nbsp;...&lt;br /&gt;想用 std::count_if() 来求ints中有多少是 &amp;gt;5 且 &amp;lt;=10 的. 这在常规代码中通常就要写一个函数来实现这个谓词:&lt;br /&gt;&amp;nbsp;if (i&amp;gt;5 &amp;amp;&amp;amp; i&amp;lt;=10) ...&lt;br /&gt;现在用bind则可以:&lt;br /&gt;&amp;nbsp;std::count_if(&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;ints.begin(),&amp;nbsp; ints.end(),&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;boost::bind(&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;std::logical_and&amp;lt;bool&amp;gt;(),&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;boost::bind(std::greater&amp;lt;int&amp;gt;(),_1,5),&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;boost::bind(std::less_equal&amp;lt;int&amp;gt;(),_1,10)));&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;span style="font-size: medium;"&gt;9.5 绑定到成员变量&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style="font-size: medium;"&gt;有:&lt;br /&gt;&amp;nbsp;map&amp;lt;int, string&amp;gt; my_map;&lt;br /&gt;&amp;nbsp;my_map[0]="Boost";my_map[1]="Bind";&lt;br /&gt;现在要输出所有元素的 second 成员. 也就是输出这些字符串. 其中的打印函数如下:&lt;br /&gt;&amp;nbsp;void print_string(const string&amp;amp; s) {&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;std::cout &amp;lt;&amp;lt; s &amp;lt;&amp;lt; '\n';&lt;br /&gt;&amp;nbsp;}&lt;br /&gt;则可以:&lt;br /&gt;&amp;nbsp;for_each(&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;my_map.begin(),&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;my_map.end(),&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;boost::bind(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;amp;print_string, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;boost::bind(&amp;amp;std::map&amp;lt;int,std::string&amp;gt;::value_type::second,_1)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;)&lt;br /&gt;&amp;nbsp;&amp;nbsp;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;汗... 看不懂bind的源码. 也不知是如何实现这些功能的. 只能等&amp;lt;&amp;lt;boost源码剖析&amp;gt;&amp;gt;出来了.&lt;/span&gt;&lt;/p&gt; &lt;br /&gt;&lt;span style="font-size: medium;"&gt;&lt;span style="color: #ff0000; font-size: medium;"&gt;&amp;nbsp;注意:&lt;/span&gt;&lt;br /&gt;(以下补于08年6月3日)&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;boost::bind() 返回的函数对象&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;会保存要绑定的实参. 而且总是拷贝一份以&lt;span style="color: #ff0000;"&gt;值的方式&lt;/span&gt;保存&lt;/span&gt;..&lt;br /&gt;这主要是考虑到被绑定的实参的生命期.&amp;nbsp;&amp;nbsp;&lt;br /&gt;但这并不总是我们期望的. 例如有时我们希望它保存指针或引用:&lt;br /&gt;&lt;br /&gt;有函数:&lt;br /&gt;void f(int &amp;amp; x) { ++x; }&lt;br /&gt;然后:&lt;br /&gt;int n = 0;&lt;br /&gt;bind(&amp;amp;f, n)();&amp;nbsp;&amp;nbsp;&amp;nbsp; //我们希望 n==1 . 但实际上没有这样...&lt;br /&gt;&lt;br /&gt;要避免这种对象复制. &amp;nbsp;而&lt;/span&gt;&lt;span style="font-size: medium;"&gt;&lt;span style="color: #0000ff;"&gt;要bind得到的函数对象保存实参的引用语义. 可以:&lt;br /&gt;&lt;/span&gt;使用 boost::&lt;span style="color: #ff0000;"&gt;ref&lt;/span&gt;()&amp;nbsp; 或 boost::&lt;span style="color: #ff0000;"&gt;cref&lt;/span&gt;() 如&lt;br /&gt;bind(&amp;amp;f, &lt;span style="color: #ff0000;"&gt;ref(n)&lt;/span&gt;)();&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //OK,&amp;nbsp; 执行后 n==1&lt;br /&gt;&lt;br /&gt;如果是绑定一个对象到它的成员函数上. 如:&lt;br /&gt;A a;&lt;br /&gt;bind(&amp;amp;A::fun, &lt;span style="color: #ff0000;"&gt;a&lt;/span&gt;);&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //则保存的是 a对象的拷贝.&lt;br /&gt;要避免这种拷贝. 除了上面提到的 ref() 外, 也可以:&lt;br /&gt;bind(&amp;amp;A::fun, &lt;span style="color: #ff0000;"&gt;&amp;amp;a&lt;/span&gt;);&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //用指针.&amp;nbsp; 反正用对象和用指针都可以. 而用指针可以避免对象拷贝的问题.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #ff0000; font-size: medium;"&gt;注意&lt;/span&gt;: (以下补于6月10日)&lt;br /&gt;bind () 的第一个参数&amp;#8212;&amp;#8212;被绑定函数&amp;#8212;&amp;#8212;是不被求值的. 如下例:&lt;br /&gt;&lt;br /&gt;typedef void (*pf)(int);&lt;br /&gt;std::vector&amp;lt;pf&amp;gt; v;&amp;nbsp; //v中有一些函数指针.&lt;br /&gt;&lt;span style="color: #ff9900;"&gt;std::for_each(v.begin(), v.end(), &lt;span style="color: #ff0000;"&gt;bind(_1, 5)&lt;/span&gt;);&lt;/span&gt;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="font-size: medium;"&gt;&lt;span style="color: #0000ff;"&gt;//想实现 _1(5);&amp;nbsp; 这样的调用. 但这样不行!&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;正确的做法是借助 &lt;span style="color: #ff0000;"&gt;boost::apply&lt;/span&gt; 模板(来自boost/bind/apply.hpp).&lt;/span&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;apply也是一个函数对象. 它的作用如下:&lt;br /&gt;apply&amp;lt;void&amp;gt;&amp;nbsp;a;&amp;nbsp;&amp;nbsp; //模板参数为函数对象的返回值类型.&lt;br /&gt;a(x);&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //相当于调用 x();&lt;br /&gt;a(x, y);&amp;nbsp;&amp;nbsp;&amp;nbsp; //相当于调用&amp;nbsp; x(y);&lt;br /&gt;a(x, y, z);&amp;nbsp; //相当于调用 x(y, z);&lt;br /&gt;所以错误的bind应该写为:&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;std::for_each(v.begin(), v.end(), bind(apply&amp;lt;void&amp;gt;(), _1, 5));&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/adylee/aggbug/2067142.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/adylee/archive/2011/06/01/2067142.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/adylee/archive/2011/05/31/2064722.html</id><title type="text">[转]boost.asio 编译</title><summary type="text">环境： VS2010,boost_1_46_1,解压缩后放在，D:\boost_1_46_1。1，编译。boost库大部分源文件是只有投文件，所以有很多库不用编译就可以使用。但是有些库是需要编译源码的。asio就需要编译。怎么去编译呢？在boost官方网站下载bjam.exe，放入boost源文件的根目录下面。因为asio依赖于其它的一些库，所以编译参数还有点复杂。然后在cmd下输入D:\boost_1_46_1&gt;bjam --with-system --with-thread --with-date_time --with-regex --with-serialization stag</summary><published>2011-05-31T07:26:00Z</published><updated>2011-05-31T07:26:00Z</updated><author><name>Ady Lee</name><uri>http://www.cnblogs.com/adylee/</uri></author><link rel="alternate" href="http://www.cnblogs.com/adylee/archive/2011/05/31/2064722.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/adylee/archive/2011/05/31/2064722.html"/><content type="html">&lt;p&gt;环境： VS2010,&lt;/p&gt;&lt;br /&gt;&lt;p&gt;boost_1_46_1,解压缩后放在，D:\boost_1_46_1。&lt;/p&gt;&lt;br /&gt;&lt;p&gt;1，编译。&lt;/p&gt;&lt;br /&gt;&lt;p&gt;boost库大部分源文件是只有投文件，所以有很多库不用编译就可以使用。但是有些库是需要编译源码的。asio就需要编译。&lt;/p&gt;&lt;br /&gt;&lt;p&gt;怎么去编译呢？在boost官方网站下载bjam.exe，放入boost源文件的根目录下面。因为asio依赖于其它的一些库，所以编译参数还有点复杂。然后在cmd下输入&lt;br /&gt;D:\boost_1_46_1&amp;gt;bjam &lt;br /&gt;--with-system --with-thread --with-date_time --with-regex &lt;br /&gt;-&lt;br /&gt;-with-serialization stage&lt;/p&gt;&lt;br /&gt;&lt;p&gt;编译完成后就可以在boost_1_46_1\stage里面找到编译好的库文件。如果在编译的时候出现编译器方面的错误，可以尝试运行C:\Program &lt;br /&gt;Files\Microsoft Visual Studio 9.0\VC\vcvarsall.bat,自动设置编译环境。&lt;/p&gt;&lt;br /&gt;&lt;p&gt;有时候你的系统上面可能装了几个版本的VS，那么怎么指定版本呢？&lt;/p&gt;&lt;br /&gt;&lt;p&gt;D:\boost_1_46_1&amp;gt;bjam --without-python --toolset=msvc-10.0 --with-thread &lt;br /&gt;--with-date_time --with-regex -&lt;br /&gt;-with-serialization stage&lt;/p&gt;&lt;br /&gt;&lt;p&gt;--without-python 表示不使用 python&lt;br /&gt;--toolset : 所使用compiler，Visual Studio &lt;br /&gt;2010為msvc-10.0&lt;br /&gt;--prefix：指定編譯後library的安裝目錄&lt;/p&gt;&lt;br /&gt;&lt;p&gt;接下来就是导入include目录boost根目录到vs中，导入编译后的lib文件目录stage\lib到lib路径中去。&lt;/p&gt;&lt;br /&gt;&lt;p&gt;vs2010:右击project-&amp;gt;properties-&amp;gt;VC++ Directories. &lt;br /&gt;将D:\boost_1_46_1加入到include directories中去，将D:\boost_1_46_1\stage\lib加入到Library &lt;br /&gt;Directories路径中去。&lt;/p&gt;&lt;br /&gt;&lt;p&gt; &lt;/p&gt;&lt;br /&gt;&lt;p&gt;2、测试。&lt;/p&gt;&lt;br /&gt;&lt;p&gt;//&amp;nbsp;&amp;nbsp; &lt;br /&gt;// timer.cpp&amp;nbsp;&amp;nbsp; &lt;br /&gt;// ~~~~~~~~~&amp;nbsp;&amp;nbsp; &lt;br /&gt;//&amp;nbsp;&amp;nbsp; &lt;br /&gt;// Copyright (c) &lt;br /&gt;2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)&amp;nbsp;&amp;nbsp; &lt;br /&gt;//&amp;nbsp;&amp;nbsp; &lt;br /&gt;// &lt;br /&gt;Distributed under the Boost Software License, Version 1.0. (See accompanying&amp;nbsp;&amp;nbsp; &lt;br /&gt;&lt;br /&gt;// file LICENSE_1_0.txt or copy at &lt;a href="http://www.boost.org/LICENSE_1_0.txt"&gt;http://www.boost.org/LICENSE_1_0.txt&lt;/a&gt;)&amp;nbsp;&amp;nbsp; &lt;br /&gt;&lt;br /&gt;//&amp;nbsp;&amp;nbsp; &lt;/p&gt;&lt;br /&gt;&lt;p&gt;#include &amp;lt;iostream&amp;gt;&amp;nbsp;&amp;nbsp; &lt;br /&gt;#include &amp;lt;boost/asio.hpp&amp;gt;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&lt;br /&gt;#include &amp;lt;boost/date_time/posix_time/posix_time.hpp&amp;gt;&amp;nbsp;&amp;nbsp; &lt;/p&gt;&lt;br /&gt;&lt;p&gt;int main()&amp;nbsp;&amp;nbsp; &lt;br /&gt;{&amp;nbsp;&amp;nbsp; &lt;br /&gt; boost::asio::io_service io;&amp;nbsp;&amp;nbsp; &lt;/p&gt;&lt;br /&gt;&lt;p&gt; boost::asio::deadline_timer t(io, boost::posix_time::seconds(5));&amp;nbsp;&amp;nbsp; &lt;br /&gt;&lt;br /&gt; t.wait();&amp;nbsp;&amp;nbsp; &lt;/p&gt;&lt;br /&gt;&lt;p&gt; std::cout &amp;lt;&amp;lt; "Hello, world!\n";&amp;nbsp;&amp;nbsp; &lt;/p&gt;&lt;br /&gt;&lt;p&gt; return 0;&amp;nbsp;&amp;nbsp; &lt;br /&gt;}&amp;nbsp; &lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;编译时提示建议添加一下编译参数来制定编译目标平台：&lt;/p&gt;&lt;br /&gt;&lt;p&gt;1&amp;gt;&amp;nbsp; Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. For &lt;br /&gt;example:&lt;br /&gt;1&amp;gt;&amp;nbsp; - add -D_WIN32_WINNT=0x0501 to the compiler command line; &lt;br /&gt;or&lt;br /&gt;1&amp;gt;&amp;nbsp; - add _WIN32_WINNT=0x0501 to your project's Preprocessor &lt;br /&gt;Definitions.&lt;br /&gt;1&amp;gt;&amp;nbsp; Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP &lt;br /&gt;target).&lt;/p&gt;&lt;br /&gt;&lt;p&gt;编译pass~~&lt;/p&gt;&lt;br /&gt;&lt;p&gt; &lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;补充一下：&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt; &lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;&lt;span style="color: #ff0000;"&gt;执行以上操作之前请执行：&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;&lt;span style="color: #ff0000;"&gt;bootstrap.bat&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;span style="color: #ff0000;"&gt;&lt;/span&gt;&lt;/strong&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;span style="color: #ff0000;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;参考：&lt;/strong&gt;&lt;/p&gt;&lt;strong&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="http://blog.csdn.net/TADICAN/archive/2009/06/17/4273004.aspx"&gt;http://blog.csdn.net/TADICAN/archive/2009/06/17/4273004.aspx&lt;/a&gt;&lt;/p&gt;&lt;/strong&gt;&lt;img src="http://www.cnblogs.com/adylee/aggbug/2064722.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/adylee/archive/2011/05/31/2064722.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/adylee/archive/2011/05/25/2056522.html</id><title type="text">IT人员简历样本（英文）</title><summary type="text">http://www.51ielts.com 2005-1-22 来源： 【无忧雅思网】Michael Needjobs3221 Need Job StreetNorth York, ONV5R 5B7Tel.(416) 123-4567--------------------------------------------------------------------------------OBJECTIVE: Seeking a challenging position as System Analyst with a growth-oriented organisation wher.</summary><published>2011-05-25T05:43:00Z</published><updated>2011-05-25T05:43:00Z</updated><author><name>Ady Lee</name><uri>http://www.cnblogs.com/adylee/</uri></author><link rel="alternate" href="http://www.cnblogs.com/adylee/archive/2011/05/25/2056522.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/adylee/archive/2011/05/25/2056522.html"/><content type="html"> &lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;font size="2"&gt;&lt;font face="Arial"&gt;http://www.51ielts.com 2005-1-22 &lt;/font&gt;&lt;font color="#990000"&gt;来源： 【无忧雅思网】&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;Michael Needjobs&lt;br /&gt;3221 Need Job Street&lt;br /&gt;North York, ON&lt;br /&gt;V5R &lt;br /&gt;5B7&lt;br /&gt;Tel.(416) &lt;br /&gt;123-4567&lt;br /&gt;&lt;br /&gt;--------------------------------------------------------------------------------&lt;br /&gt;&lt;br /&gt;OBJECTIVE: &lt;br /&gt;Seeking a challenging position as System Analyst with a growth-oriented &lt;br /&gt;organisation where my skills, experience will be utilised to their full &lt;br /&gt;potential.&lt;br /&gt;&lt;br /&gt;WORK EXPERIENCE:&lt;br /&gt;&lt;br /&gt;May 1994-Present Employer: BEST SYSTEM &lt;br /&gt;INC., Markham, Ontario&lt;br /&gt;&lt;br /&gt;Position: System Analyst&lt;br /&gt;&lt;br /&gt;designed and &lt;br /&gt;implemented complex GUI and RDBMS applications under WINDOWS NT environment &lt;br /&gt;using Visual C++, MFC, C, Visual Basic 4, SQL Server 6, Access 2.0&lt;br /&gt;member of &lt;br /&gt;a development team for a large client server (three tier) relational database &lt;br /&gt;application using Visual Basic, remote automation, remote databases and SQL &lt;br /&gt;server under WINDOWS NT environment.&lt;br /&gt;redeveloped and reengineered several &lt;br /&gt;applications of serial communication and databases&lt;br /&gt;&lt;br /&gt;1993 - Apr.1994 &lt;br /&gt;Employer: SINUS INTERNATIONAL INC., Toronto, Ontario&lt;br /&gt;&lt;br /&gt;Position: Programmer &lt;br /&gt;Analyst&lt;br /&gt;&lt;br /&gt;designed, developed and tested communication software written in &lt;br /&gt;C for DOS and UNIX, based on custom communication protocol&lt;br /&gt;designed &lt;br /&gt;relational database applications on UNIX environment&lt;br /&gt;supported and managed &lt;br /&gt;the activity of a Novell network&lt;br /&gt;1991-1993 Employer: ALEGRA Ltd, Oradea, &lt;br /&gt;Romania&lt;br /&gt;&lt;br /&gt;Position: R&amp;amp;D Engineer&lt;br /&gt;&lt;br /&gt;designed and developed &lt;br /&gt;structured software applications in C (DOS/WINDOWS), C++, Pascal&lt;br /&gt;designed &lt;br /&gt;database applications dBase and Fox-Pro&lt;br /&gt;co-ordinated and supervised the whole &lt;br /&gt;activity in a NOVELL computer network&lt;br /&gt;taught public courses 10 hours/week &lt;br /&gt;about computer programming&lt;br /&gt;July-Sept. Environment: University of Coimbra &lt;br /&gt;(Portugal)&lt;br /&gt;&lt;br /&gt;1990 Position: R&amp;amp;D Engineer&lt;br /&gt;&lt;br /&gt;summer courses on data &lt;br /&gt;transmission, remote connections to servers, &lt;br /&gt;Internet&lt;br /&gt;&lt;br /&gt;--------------------------------------------------------------------------------&lt;br /&gt;&lt;br /&gt;PERSONAL &lt;br /&gt;STRENGTHS:&lt;br /&gt;&lt;br /&gt;six years of extensive work experience in various aspects of &lt;br /&gt;computer programming, analysis, developing and testing&lt;br /&gt;able to optimise &lt;br /&gt;programs, to use difficult algorithms and protocol specifications, to work in a &lt;br /&gt;team environment or unsupervised&lt;br /&gt;able to co-ordinate the analysis and &lt;br /&gt;production a development team&lt;br /&gt;excellent programming abilities in C (DOS &amp;amp; &lt;br /&gt;UNIX), Visual C++, Visual Basic, SQL server, Access&lt;br /&gt;very good working &lt;br /&gt;knowledges with computer networks (Novell and TCP/IP)&lt;br /&gt;well-organised, &lt;br /&gt;efficient, quick learner, self-motivated and excellent mathematics &lt;br /&gt;background&lt;br /&gt;excellent ability to plan, organise, prioritise my work and to &lt;br /&gt;meet on time the deadlines&lt;br /&gt;EDUCATION AND TRAINING:&lt;br /&gt;&lt;br /&gt;1986-1991 Computer &lt;br /&gt;and Control Engineering Faculty&lt;br /&gt;University of Timisoara/Romania&lt;br /&gt;Master of &lt;br /&gt;Science Degree in Computer Engineering&lt;br /&gt;&lt;br /&gt;1991-1994 International Business &lt;br /&gt;Relations Faculty&lt;br /&gt;University of Timisoara/Romania&lt;br /&gt;&lt;br /&gt;1995 Seneca College &lt;br /&gt;- Advanced C++ Course&lt;br /&gt;Microsoft - Advanced C++ Course&lt;br /&gt;&lt;br /&gt;PAPERS, &lt;br /&gt;DISSERTATIONS AND AWARDS:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;1986-1989 prizes at the Graduate Student &lt;br /&gt;National Mathematics Contest&lt;br /&gt;June 1994 Member in Romanian Engineers &lt;br /&gt;Association&lt;br /&gt;SPECIAL INTERESTS:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Object Oriented Programming, &lt;br /&gt;Numerical Models, Data Communication&lt;br /&gt;HOBBIES:&lt;br /&gt;&lt;br /&gt;Hiking, tennis, music &lt;br /&gt;and reading&lt;br /&gt;LANGUAGES:&lt;br /&gt;&lt;br /&gt;English, French, German and &lt;br /&gt;Romanian&lt;br /&gt;REFERENCES:&lt;br /&gt;&lt;br /&gt;Available upon request &lt;/p&gt;&lt;!--学校广告开始--&gt;&lt;!--学校广告结束--&gt;&lt;img src="http://www.cnblogs.com/adylee/aggbug/2056522.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/adylee/archive/2011/05/25/2056522.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/adylee/archive/2011/02/22/1961545.html</id><title type="text">[转]VC和c++ builder DLL互调用</title><summary type="text">常在江湖飘，少不了要和DLL打交道。有时我们需要使用C++Builder编写一个DLL，然后拿到VC中用（比如用C++Builder写一个窗体封装到DLL）；有时又要拿VC编写的DLL在C++Builder使用（比如拿到一个产品的开发包，这个包是一堆用VC写的DLL）。很遗憾，由于MS和Borland（CodeGear）两家的编辑器实现细节不同，造成了它们生成的DLL不能相互通用，因此给实际带来了很多的麻烦。下面来说一说如何解决这个问题。一、VC生成DLL，C++Builder调用。1、用extern "C"修饰VC导出的DLL函数。如：extern "C&amp;quo</summary><published>2011-02-22T09:48:00Z</published><updated>2011-02-22T09:48:00Z</updated><author><name>Ady Lee</name><uri>http://www.cnblogs.com/adylee/</uri></author><link rel="alternate" href="http://www.cnblogs.com/adylee/archive/2011/02/22/1961545.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/adylee/archive/2011/02/22/1961545.html"/><content type="html">常在江湖飘，少不了要和DLL打交道。有时我们需要使用C++Builder编写一个DLL，然后拿到VC中用（比如用C++Builder写一个窗体封装到DLL）；有时又要拿VC编写的DLL在C++Builder使用（比如拿到一个产品的开发包，这个包是一堆用VC写的DLL）。&lt;br /&gt;很遗憾，由于MS和Borland（CodeGear）两家的编辑器实现细节不同，造成了它们生成的DLL不能相互通用，因此给实际带来了很多的麻烦。下面来说一说如何解决这个问题。&lt;br /&gt;一、VC生成DLL，C++Builder调用。&lt;br /&gt;1、用extern "C"修饰VC导出的DLL函数。如：extern "C" __declspec(dllexport) int aFunc(int a);&lt;br /&gt;2、用C++Builder的implib工具生成DLL对应的lib文件。如：implib -a xxx.lib xxx.dll（注意，implib一定要带-a开关）。生成lib文件之后，C++Builder便可以使用这个lib文件了。&lt;br /&gt;&lt;br /&gt;二、C++Builder生成DLL，VC调用。&lt;br /&gt;1、用extern "C"修饰C++Builder导出的DLL函数。如：extern "C" __declspec(dllexport) int aFunc(int a);&lt;br /&gt;2、用C++Builder的impdef工具生成DLL对应的def文件。如：impdef xxx.def xxx.dll。&lt;br /&gt;3、用记事本打开xxx.def文件，删去每个函数名前的"_"。如原来的def文件为：&lt;br /&gt;&lt;dl class="code"&gt;&lt;dt&gt;C/C++ code &lt;dd&gt;&lt;div&gt;&lt;span style="color: #000000"&gt;&lt;br/&gt;LIBRARY     XXX.DLL&lt;br/&gt;&lt;br/&gt;EXPORTS&lt;br/&gt;    ___CPPdebugHook                @&lt;/span&gt;&lt;span style="color: #800080"&gt;2&lt;/span&gt;&lt;span style="color: #000000"&gt;   ; ___CPPdebugHook&lt;br/&gt;    _aFunc                         @&lt;/span&gt;&lt;span style="color: #800080"&gt;1&lt;/span&gt;&lt;span style="color: #000000"&gt;   ; _aFunc&lt;br/&gt;&lt;/span&gt;&lt;/div&gt;&lt;/dd&gt;&lt;/dl&gt;&lt;br /&gt;那么删除后就变成了：&lt;br /&gt;&lt;dl class="code"&gt;&lt;dt&gt;C/C++ code &lt;dd&gt;&lt;div&gt;&lt;span style="color: #000000"&gt;&lt;br/&gt;LIBRARY     XXX.DLL&lt;br/&gt;&lt;br/&gt;EXPORTS&lt;br/&gt;    __CPPdebugHook                @&lt;/span&gt;&lt;span style="color: #800080"&gt;2&lt;/span&gt;&lt;span style="color: #000000"&gt;   ; ___CPPdebugHook&lt;br/&gt;    aFunc                         @&lt;/span&gt;&lt;span style="color: #800080"&gt;1&lt;/span&gt;&lt;span style="color: #000000"&gt;   ; _aFunc&lt;br/&gt;&lt;/span&gt;&lt;/div&gt;&lt;/dd&gt;&lt;/dl&gt;&lt;br /&gt;4、用VC的LIB工具，根据上面的def文件生成lib文件。如：LIB /DEF:XXX.def。生成lib文件之后，VC便可以使用这个lib文件了。&lt;br /&gt;&lt;br /&gt;综上说来，两种工具开发的DLL在相互使用的时候，主要的问题便是lib库的问题，能把这一问题解决好行了。&lt;img src="http://www.cnblogs.com/adylee/aggbug/1961545.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/adylee/archive/2011/02/22/1961545.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/adylee/archive/2010/12/02/1894283.html</id><title type="text">[转]c++builder调用VC的dll以及VC调用c++builder的dll</title><summary type="text">解析__cdecl，__fastcall， __stdcall 的不同:在函数调用过程中，会使用堆栈，这三个表示不同的堆栈调用方式和释放方式。 比如说__cdecl，它是标准的c方法的堆栈调用方式，就是在函数调用时的参数压入堆栈是与函数的声明顺序相反的，其它两个可以看MSDN，不过这个对我们编程没有太大的作用 --------------------------------------------------------------- 调用约定 调用约定(Calling convention)决定以下内容：函数参数的压栈顺序，由调用者还是被调用者把参数弹出栈，以及产生函数修饰名的方法。MFC支</summary><published>2010-12-02T03:47:00Z</published><updated>2010-12-02T03:47:00Z</updated><author><name>Ady Lee</name><uri>http://www.cnblogs.com/adylee/</uri></author><link rel="alternate" href="http://www.cnblogs.com/adylee/archive/2010/12/02/1894283.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/adylee/archive/2010/12/02/1894283.html"/><content type="html">&lt;p&gt;解析__cdecl，__fastcall， __stdcall 的不同:&lt;br /&gt;在函数调用过程中，会使用堆栈，这三个表示不同的堆栈调用方式和释放方式。 &lt;br /&gt;比如说__cdecl，它是标准的c方法的堆栈调用方式，就是在函数调用时的参数压入堆栈是与函数的声明顺序相反的，其它两个可以看MSDN，不过这个对我们编程没有太大的作用 &lt;br /&gt;--------------------------------------------------------------- &lt;br /&gt;调用约定 &lt;br /&gt;调用约定(Calling convention)决定以下内容：函数参数的压栈顺序，由调用者还是被调用者把参数弹出栈，以及产生函数修饰名的方法。MFC支持以下调用约定： &lt;br /&gt;_cdecl &lt;br /&gt;按从右至左的顺序压参数入栈，由调用者把参数弹出栈。对于"C"函数或者变量，修饰名是在函数名前加下划线。对于"C++"函数，有所不同。 &lt;br /&gt;如函数void test(void)的修饰名是_test；对于不属于一个类的"C++"全局函数，修饰名是&lt;a href="&amp;#109;&amp;#97;&amp;#105;&amp;#108;&amp;#116;&amp;#111;&amp;#58;&amp;#95;&amp;#116;&amp;#101;&amp;#115;&amp;#116;&amp;#64;&amp;#64;&amp;#90;&amp;#65;&amp;#88;&amp;#88;&amp;#90;"&gt;_test@@ZAXXZ&lt;/a&gt;（怎么感觉像乱码？？）。 &lt;br /&gt;这是MFC缺省调用约定。由于是调用者负责把参数弹出栈，所以可以给函数定义个数不定的参数，如printf函数。 &lt;br /&gt;_stdcall &lt;br /&gt;按从右至左的顺序压参数入栈，由被调用者把参数弹出栈。对于"C"函数或者变量，修饰名以下划线为前缀，然后是函数名，然后是符号"@"及参数的字节数，如函数int func(int a, double b)的修饰名是&lt;a href="&amp;#109;&amp;#97;&amp;#105;&amp;#108;&amp;#116;&amp;#111;&amp;#58;&amp;#95;&amp;#102;&amp;#117;&amp;#110;&amp;#99;&amp;#64;&amp;#49;&amp;#50;"&gt;_func@12&lt;/a&gt;。对于"C++"函数，则有所不同。所有的Win32 API函数都遵循该约定。 &lt;br /&gt;_fastcall &lt;br /&gt;头两个DWORD类型或者占更少字节的参数被放入ECX和EDX寄存器，其他剩下的参数按从右到左的顺序压入栈。由被调用者把参数弹出栈，对于"C"函数或者变量，修饰名以"@"为前缀，然后是函数名，接着是符号"@"及参数的字节数，如函数int func(int a, double b)的修饰名是@func@12。对于"C++"函数，有所不同。&lt;br /&gt;未来的编译器可能使用不同的寄存器来存放参数。&lt;/p&gt;&lt;p&gt;Dll中用 __declspec(dllexport)声明的函数:&lt;br /&gt;__declspec(dllexport)只是表示这个函数是一个DLL导出函数,而__stdcall是一种函数调用约定,两者应该是没有冲突的.&amp;nbsp;&amp;nbsp; &lt;br /&gt;如:__declspec(dllexport)&amp;nbsp; void&amp;nbsp; __stdcall&amp;nbsp; aTry();&lt;/p&gt;&lt;p&gt;c++builder和vc描述符定义的区别&lt;br /&gt;在c++builder中&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; __cdecl的函数输出前会带："_"&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; __stdcall无特征,只输出函数名&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; __fastcall函数输出前带："@"&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 都无"@nn"后缀格式！&lt;br /&gt;在vc中&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; __cdecl无特征,只输出函数名&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; __stdcall的函数输出前会带："_" 后缀带："@nn"&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; __fastcall函数输出前带："@"后缀带："@nn&lt;/p&gt;&lt;p&gt;c++builder调用VC的dll:&lt;br /&gt;在VC中编写DLL时，使用了.def文件，在出口函数声明时也在前面加上了__declspec(dllexport)说明。把VC生成的DLL文件放在了当前目录下，使用BCB的命令行工具implib生成的.lib文件，具体格式为implib bcb.lib vc.dll，再把implib根据dll生成的LIB文件加入到工程中，再在工程中加入DLL出口函数的声明（函数名前加上了WINAPI,即__stdcall；每个函数定义的最前面也加上了__declspec(dllimport)）。&lt;br /&gt;而且由于BCB和VC++成立函数名转换的做法不同。所以在VC中最好是输出函数为C函数的DLL，如果输出函数是C++类，则可能无法调用。&lt;br /&gt;我的解决办法（经过本人实验证明的，共2种）&lt;br /&gt;方法1：VC编译c文件生成dll时导出函数头文件加上extern "C"{}关键字，函数声明和定义处再加调用约定描述符__cdecl，然后将函数声明和定义处都加上一个下划线就没有问题了。&lt;br /&gt;EXAMPLE:&lt;br /&gt;假设我VC的dll中包含int myFunction(void)，.c文件中函数实现处的正确写法是：&lt;br /&gt;__declspec(dllexport) int __cdecl _myFunction(void)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // add your code here&lt;br /&gt;}&lt;br /&gt;.h文件中函数声明处的正确写法如下&lt;br /&gt;__declspec(dllexport) int __cdecl _myFunction(void);&lt;br /&gt;BCB调用时只要包含lib文件，具体操作步骤：&lt;br /&gt;运行implib bcb.lib vc.dll&lt;br /&gt;project-&amp;gt;add to...下拉框中选择.lib类型，打开刚才通过implib和vc的dll生成的lib文件&lt;br /&gt;在工程中用到dll的.c源文件中包含该dll的头文件&lt;br /&gt;调用时直接写 int i = myFunction(); 即可。&lt;/p&gt;&lt;p&gt;方法2：仅对VC编译C文件生成dll时有效，导出函数头文件加上extern "C"{}关键字。BCB的Project-&amp;gt;option-&amp;gt;advanced compiler下的Calling convention中选择Stdcall就可以直接调用VC的.c文件编译生成的动态链接库了。&lt;/p&gt;&lt;p&gt;VC调用c++builder的dll: (参考：MSDN2000)&lt;br /&gt;VC中无LIB时的DLL隐式链接,制作与VC++相符合的LIB函数符号输入库（转）请大家注意!这种方法只能应用于输出为C格式的__stdcall调用方式！&lt;br /&gt;1.使用VC++的工具DUMPBIN将DLL中的导出函数表导出到一定义(.DEF)文件&lt;br /&gt;EXAMPLE：&lt;br /&gt;DUMPBIN VideoDeCoder.dll /EXPORTS /OUT:VideoDeCoder.def&lt;br /&gt;2.将导出的.DEF文件整理为一符合.DEF个数的函数导出文件(整理过程巨乱巨复杂，懒得举例了，后面有简便方法^_^)&lt;br /&gt;3.使用VC++的LIB工具,带/DEF:(.def文件名) /MACHINE:IX86(80X86机器),就输出符合VC++格式的的LIB文件了.&lt;br /&gt;EXAMPLE:&lt;br /&gt;LIB/DEF:VideoDeCoder.def /MACHINE:IX86&lt;br /&gt;4.连接时带上LIB文件链接;注意的是当有些动态库DUMPBIN的只有函数名,无"@nn"的参数格式,如C++Builder写的DLL,输出就只有函数名符号,链接时就会报错:&lt;br /&gt;error LNK2002:unresolved external symbol "&lt;a href="&amp;#109;&amp;#97;&amp;#105;&amp;#108;&amp;#116;&amp;#111;&amp;#58;&amp;#102;&amp;#117;&amp;#110;&amp;#99;&amp;#116;&amp;#105;&amp;#111;&amp;#110;&amp;#110;&amp;#97;&amp;#109;&amp;#101;&amp;#64;&amp;#110;&amp;#110;"&gt;functionname@nn&lt;/a&gt;"&lt;br /&gt;提示程序中引入的函数符号无法识别,这时只要将DEF文件中相应的函数名称改为&lt;a href="&amp;#109;&amp;#97;&amp;#105;&amp;#108;&amp;#116;&amp;#111;&amp;#58;&amp;#102;&amp;#117;&amp;#110;&amp;#99;&amp;#116;&amp;#105;&amp;#111;&amp;#110;&amp;#110;&amp;#97;&amp;#109;&amp;#101;&amp;#64;&amp;#110;&amp;#110;"&gt;functionname@nn&lt;/a&gt;方式,重新建立LIB,重新链接即可.&lt;br /&gt;这样就制作成功了符合VC调用方式的LIB了！&lt;/p&gt;&lt;p&gt;要值得一说的是！BORLAND C++BUILDER有一个很好的工具IMPDEF可以直接将DLL中的函数输出到.DEF文件中，这种方法只能应用于输出为C格式的__stdcall调用方式，只要做一点点修改就可以成为符合VC的DEF文件！&lt;br /&gt;IMPDEF xxx.def xxx.dll&lt;br /&gt;只要将BCB的DEF文件中函数申明格式转换为vc识别的格式就可以利用LIB工具生成LIB；要使用C分格输出(extern "C")才是必须的！而且别忘了在DEF文件中的函数申明不要带&amp;#8220;_&amp;#8221;啊！：）不然会出现error LNK2001的链接错误！&lt;br /&gt;vc调用bcb的我没试过，不过可以参照上面的格式自己改改好了：）&lt;/p&gt;&lt;p&gt;本文来自CSDN博客，转载请标明出处：&lt;a href="http://blog.csdn.net/helenhf/archive/2007/03/16/1531002.aspx"&gt;http://blog.csdn.net/helenhf/archive/2007/03/16/1531002.aspx&lt;/a&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/adylee/aggbug/1894283.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/adylee/archive/2010/12/02/1894283.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry></feed>
