std::bind與std::ref, why and how

Fun_with_Words發表於2021-12-26

首先解釋下為什麼有時候需要bind. 我們可以用bind從函式T add(T a, T b)造出個inc()來,即把b寫死為1。這個例子本身比較傻,但有不傻的應用。

template<typename T> T add(T a, T b) { return a + b; }

template<typename T> auto get_inc() { 
    T b = 1;
    return bind(add<T>, std::placeholders::_1, b); 
}

    std::function<int(int)> inc = get_inc<int>();
    printf("%d\n", inc(2));

其次為啥bind預設傳copy而不是reference? get_inc()返回後, 它裡面的b就沒了,stack frame供別的函式用去了。傳引用的話就引錯地方了。

可有時候很需要傳應用,如兩個vector相加,而且我們知道引用是有效的:

#include <stdio.h>
#include <vector>
#include <functional>
using namespace std;

struct vec : public vector<int> {
    vec() {}
    vec(const vec&) { puts("vec(const vec&)"); }
    vec& operator=(const vec&) { puts("operator=(const vec&)"); return *this; }
};

void addv(const vec& a, const vec& b) {} // 沒有返回值不重要

int main() {
    std::function<int(int)> inc = get_inc<int>();
    printf("%d\n", inc(2));
    
    vec a, one;
    auto incv = bind(addv, std::placeholders::_1, ref(one));
    incv(a);
}

如果把ref(one)換成one,可看到copy constructor被呼叫。可以在某個函式裡new個vec* v, 再ref(*v),最後某處delete v.

std::ref是如何實現的?Function templates ref and cref are helper functions that generate an object of type std::reference_wrapper, using template argument deduction to determine the template argument of the result. [cppreference]

How does c++11 std::ref work? - Stack Overflow  我搞了個指標版:

template<class T> struct myref_wrapper {
    T* p;
    myref_wrapper(T& t) : p(&t) {}
    T& operator()() { return *p; }
};

template<class T> myref_wrapper<T> myref(T& t) { return myref_wrapper<T>(t); }

    int i = 0;
    myref(i)() = 1;
    printf("%d\n", i);

真是人生苦短,我學python啊。c++ - Implementation of std::reference_wrappestd::bind簡單使用 - 部落格園  Passing reference with std::ref in C++

operator()(T&& t) { *target = std::move(t); } std::move可以開新帖了。

相關文章