C 11新特性のstd::functionとstd::bind

5645 ワード

1.stdとは:function
std::functionは実はクラステンプレートで、cの関数ポインタの概念を含んでいます.
クラステンプレートstd::functionは汎用的で多状態の関数パッケージである.std::functionのインスタンスは、通常の関数、Lambda式、関数ポインタ、および他の関数オブジェクトなどを含む呼び出し可能な任意のターゲットエンティティを格納、コピー、および呼び出し操作することができる.
簡単に言えば、std::functionはすべての呼び出し可能なエンティティをカプセル化し、新しいstd::functionオブジェクトを形成します.ユーザーは使用時にエンティティを一つ一つ呼び出す必要はありません.新しいstd::functionを使用して各エンティティを呼び出す必要があります.
次のようにstd::functionはコールバック関数として使用され、2つのintパラメータの戻り値がintのオブジェクトを呼び出すことができます.
#include 
#include 
#include 
using namespace std;

//   C  
int c_function(int a, int b)
{
    return a + b;
}

//     
class Functor
{
public:
    int operator()(int a, int b)
    {
        return a + b;
    }
};

int main(int argc, char** argv)
{
    Functor functor;
    std::list<:function int="">> callables;

    callables.push_back(c_function);
    callables.push_back(functor);
    callables.push_back([](int x, int y)->int{
        return x + y;
    });

    for (const auto& e : callables)
    {
        cout << e(3, 4) << endl;
    }
}

2.std::functionをパラメータとして
またstd::functionはcの関数ポインタと互換性があるため、関数ポインタの特性も含まれている.しかし、関数ポインタとは異なり、関数ポインタは1つの関数のみを指すが、std::functionは、関数として呼び出すことができる任意のオブジェクトを指すことができる.以下の内容は、
2.1伝達値に基づく方式伝達パラメータ
void registerCallBack(std::function);

2.2参照に基づく入力パラメータ
initWithFunctionを呼び出すと一時的なstd::functionオブジェクトが生成され、右の値に属し、constを使用する必要があります.そうしないと、エラーが発生します.
bool CallFunc::initWithFunction(const std::function &func)
{
    _function = func;
    return true;
}

2.3 std::functionの保存
転送操作std::move効率が向上
class CallBackHolder 
{
public:
  void registerCallBack(std::function func)
  {
    callback = std::move(func);
  } 
private:
  std::function callback; 
}

3.クラスのメンバー関数を関数として参照
3.1 std::bind()とstd::functionを使用して実現
std::bindはエンティティと関数アドレスのバインドを完了しました.そのパラメータにはオブジェクトポインタと関数ポインタがあるので、std::functionを作成しました.そしてstd::functionはそのthisポインタを正しく処理すれば、正しく呼び出すことができます.
class RTree

{
public:
         void searchOverlap(std::functionf)
         {
                   f(2);
         }
};

class CallRtree
{
public:
         virtual void searchRes(int a)
         {
                   this->a = a;
         }
         void search()
         {
                   RTree rtree;
                   std::functionfunctional = std::bind(&CallRtree::searchRes, this, std::placeholders::_1);
                  //       auto a =std::bind(....);
                   rtree.searchOverlap(functional);
                   int v = this->a;
         }

private:
         int a;
}
int _tmain(intargc, _TCHAR* argv[])

{
         CallRtree caller;
         caller.search();
}

3.2 lambda式で実現(先に言わないで、後でlamdbaを復習してから)
2.stdとは何か::bind
  • は、関数、メンバー関数、および閉パケットをfunction関数オブジェクト
  • に変換する.
  • 多重(n>1)関数を1元関数または(n−1)元関数に変換する.

  • bindは、指定した呼び出し可能なエンティティのいくつかのパラメータを既存の変数にバインドして、新しい呼び出し可能なエンティティを生成するメカニズムです.汎用関数アダプタとして、呼び出し可能なオブジェクトを受信し、元のオブジェクトに適応するための新しい呼び出し可能なオブジェクトのパラメータリストを生成します.
    2.1 bindの使い方
    たとえば、このような関数check_が存在します.size、これは二元関数なのでfind_としてifのパラメータ、エラーが発生します.なぜならfind_ifは1元関数しか受け入れられませんが、どうやって解決しますか?一つの方法はLambda式で、もう一つの方法はstd::bindを使用することです.
    bool check_size(const string &s,string::size_type sz)
    {
          return s.size()>=sz;
    }
    

    次のbindの関数は1つのプレースホルダしかありません.つまり、1つのパラメータを入力するだけです.check_sizeの2番目のパラメータはszにバインドされ、szの値はcheck_です.sizeの2番目のパラメータの値、check_size最初のパラメータは入力する必要があります
    auto wc = find_if(words.begin(),words.end(),bind(check_size,_1,sz));
    

    2.2 bindのパラメータ問題
    auto g = bind(f,a,b,_2,c,_1);
    

    g(3,5)を呼び出すとbind(f,a,b,5,c,3)に相当する.だから1は伝達された最初のパラメータに相当し、2伝達された2番目のパラメータに相当します...このように推す.
    注意:bindは直接バインドされた値に対して、値で伝達されます.1のように、リファレンス伝達を使用します.bindの戻り値は呼び出すことができるエンティティなので、通常はfunctionと組み合わせて使用します.
    2.3 bind参照パラメータ
    バインドされたパラメータの中には、参照で渡すか、バインドするパラメータがコピーできない場合があります.たとえばostreamストリームオブジェクトはコピーできません.コピーせずにbindに渡したい場合は、refを使用する必要があります.refは、指定された参照を含むオブジェクトを返し、コピーできます.
    for_each(words.begin(),words.end,bind(print,ref(os),_1,' '));
    

    2.4 std::bindバインドメンバー関数と静的メンバー関数
    メンバー関数のバインドには、呼び出し元、すなわちクラスのインスタンスが必要です.重荷重関数のパラメータ個数が異なる場合、bindもその意味を失うため、bindは重荷重関数をバインドできないことに注意してください.
    class Utils {  
    public:  
        Utils(const char* name) {  
            strcpy(_name, name);  
        }        
        void sayHello(const char* name) const {  
            std::cout << _name << " say: hello " << name << std::endl;  
        }        
        static int getId() {  
            return 10001;  
        }         
        int operator()(int i, int j, int k) const {  
            return i + j + k;  
        }       
    private:  
        char _name[32];  
    };  
    
    int main(void) {  
    
        //         
        Utils utils("Vicky");  
        auto sayHello = std::bind(&Utils::sayHello, utils/*   */, std::placeholders::_1);  
        sayHello("Jack");  
    
        //           
        auto getId = std::bind(&Utils::getId);  
        std::cout << getId() << std::endl; 
    }
    

    2.5 bindとfunctionの組み合わせ
    cococos 2 dxのソースコードではfunctionが関数パラメータとしてよく見られ,bindが実パラメータとして伝達される
    bool Label::multilineTextWrap(std::function nextTokenLen)
    {}
    
    bool Label::multilineTextWrapByChar()
    {
          return multilineTextWrap(std::bind(getFirstCharLen, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
    }