c++11之std::bind簡單使用


note

  • 更多用法,請參考: cppreference
  • 用的少,容易忘。

我的理解

  • 類似延遲計算。 比如,回調函數,將回調函數傳入后,回調函數不一定馬上被調用。
  • 它是一個模板類,調用后將生成一個新的調用對象A。調用該對象A與調用原函數是等價的。

聲明

截至目前,它的聲明如下

需要包含頭文件

#include <functional>

一個例子

代碼

下面的print函數負責輸出參數的值, 通過使用std::bind, 生成一個新的對象 func, 此時, func(a, b, c);print(a, b, c);**的調用結果是等價的。

#include <functional>

void print(int a, int b, int c)
{
	std::cout << "a = " << a << ", b=" << b << ", c=" << c << "\n\n";
}

int main(int argc, char* argv[], char* env[])
{
	auto func = std::bind(print, std::placeholders::_2, 2, std::placeholders::_1);

	func(3, 4);
        
        return 0;
}

std::placeholders 說明

std::placeholders::_2std::placeholders::_1表示參數的順序,比如, 上面的代碼示例中, 3是func的第一個參數,但是,func在聲明時,指定了第一個參數的位置,放在了最后。 所以,上面的代碼輸出結果: a=4, b=2, c=3

注意

  • std::bind的函數參數默認使用的是拷貝, 如果需要使用引用,則需要配合std::ref
  • 下面一個例子,幫助理解。
    print2函數負責輸出參數的值,且參數都是引用, print2函數內完成對參數的自增
#include <functional>

void print2(int &a, int &b)
{
	std::cout << "函數調用:a=" << a << ", b=" << b << "\n";
	++a;
	++b;
}

int main(int argc, char* argv[], char* env[])
{

	int a = 1;
	int b = 2;

	auto func2 = std::bind(print2, a, std::ref(b));

	std::cout << "調用前,a=" << a << ", b=" << b << "\n";
	func2();
	std::cout << "調用后,a=" << a << ", b=" << b << "\n";

        return 0;
}

調用時,盡管都采用了傳入引用的方式,但略有不同。參數a使用的是傳統的方式,參數b采用的是 std::ref的方式。 觀察輸出結果

可以看到,std::bind的參數是以 拷貝的方式,使用 std::ref 的方式可以實現參數在std::bind的引用。

官方的例子

#include <random>
#include <iostream>
#include <memory>
#include <functional>
 
void f(int n1, int n2, int n3, const int& n4, int n5)
{
    std::cout << n1 << ' ' << n2 << ' ' << n3 << ' ' << n4 << ' ' << n5 << '\n';
}
 
int g(int n1)
{
    return n1;
}
 
struct Foo {
    void print_sum(int n1, int n2)
    {
        std::cout << n1+n2 << '\n';
    }
    int data = 10;
};
 
int main()
{
    using namespace std::placeholders;  // for _1, _2, _3...
 
    // demonstrates argument reordering and pass-by-reference
    int n = 7;
    // (_1 and _2 are from std::placeholders, and represent future
    // arguments that will be passed to f1)
    auto f1 = std::bind(f, _2, 42, _1, std::cref(n), n);
    n = 10;
    f1(1, 2, 1001); // 1 is bound by _1, 2 is bound by _2, 1001 is unused
                    // makes a call to f(2, 42, 1, n, 7)
 
    // nested bind subexpressions share the placeholders
    auto f2 = std::bind(f, _3, std::bind(g, _3), _3, 4, 5);
    f2(10, 11, 12); // makes a call to f(12, g(12), 12, 4, 5);
 
    // common use case: binding a RNG with a distribution
    std::default_random_engine e;
    std::uniform_int_distribution<> d(0, 10);
    auto rnd = std::bind(d, e); // a copy of e is stored in rnd
    for(int n=0; n<10; ++n)
        std::cout << rnd() << ' ';
    std::cout << '\n';
 
    // bind to a pointer to member function
    Foo foo;
    auto f3 = std::bind(&Foo::print_sum, &foo, 95, _1);
    f3(5);
 
    // bind to a pointer to data member
    auto f4 = std::bind(&Foo::data, _1);
    std::cout << f4(foo) << '\n';
 
    // smart pointers can be used to call members of the referenced objects, too
    std::cout << f4(std::make_shared<Foo>(foo)) << '\n'
              << f4(std::make_unique<Foo>(foo)) << '\n';
}

官方例子輸出

2 42 1 10 7
12 12 12 4 5
1 5 0 2 0 8 2 2 10 8
100
10
10
10


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM