2017-07-26 82 views
0

我想通過一個mem_fn參數bind但編譯器似乎不允許它。爲什麼我不能在綁定中使用mem_fn Functor?

例如這工作正常:

accumulate(cbegin(foos), cend(foos), 0, bind(plus<int>(), placeholders::_1, bind(&foo::r, placeholders::_2))); 

但是當我嘗試使用mem_fn函子我得到錯誤的頁面:

accumulate(cbegin(foos), cend(foos), 0, bind(plus<int>(), placeholders::_1, mem_fn(&foo::r))); 

/usr/include/c++/6/bits/stl_numeric.h: In instantiation of ‘_Tp std::accumulate(_InputIterator, _InputIterator, _Tp, _BinaryOperation) [with _InputIterator = __gnu_cxx::__normal_iterator >; _Tp = int; _BinaryOperation = std::_Bind(std::_Placeholder<1>, std::_Mem_fn)>]’:
prog.cpp:20:102: required from here
/usr/include/c++/6/bits/stl_numeric.h:154:22: error: no match for call to ‘(std::_Bind(std::_Placeholder<1>, std::_Mem_fn)>) (int&, foo* const&)’

+0

你是第一人,我看到使用'bind'的特殊處理嵌套綁定表達式而不知道它。 –

+0

mem_fn已棄用,請勿使用它。 –

+1

@ n.m。它是?我知道它內部的typedefs將在C++ 17中,但我沒有看到有關'mem_fn'本身的任何內容被棄用。 – NathanOliver

回答

0

要理解這一點,請思考如果您只是將文字傳遞給bind的3 rd參數,這將意味着什麼。例如,如果你做了:

accumulate(cbegin(foos), cend(foos), 0, bind(plus<int>(), placeholders::_1, 13)) 

結果將是size(foos) * 13,因爲plus會用13,因爲它是在每次迭代加數。

accumulate(cbegin(foos), cend(foos), 0, bind(plus<int>(), placeholders::_1, mem_fn(&foo::r))) 

不能編譯,因爲它試圖爲被加數plus傳遞的mem_fn(&foo::r)結果。既然不能轉換成intplus不能接受。但即使它可以轉換爲int,但這不是您要查找的內容,您需要參數並致電foo::r,並將結果傳遞給plus。因此我們知道我們需要看到,在該陳述中的某處使用placeholders::_2,傳達了其調用r方法的參數。


我們需要綁定placeholders::_2綁定到一個仿函數,它將調用該方法r上它的參數。綁定當然需要bind,但實際上bind can take a method as it's 1st argument

也就是說,您的工作代碼中的bind(&foo::r, placeholders::_2)聲明在非嵌套窗體中沒有任何意義;該仿函數甚至不需要2個參數!實際上具有special rules for handling a bind nested within another bind,使得它們可以共享外bind的佔位符,恐怕沒有的方式來傳達綁定參數嵌套表達式:

If the stored argument arg is of type T for which std::is_bind_expression<T>::value == true (for example, another bind expression was passed directly into the initial call to bind), then bind performs function composition: instead of passing the function object that the bind subexpression would return, the subexpression is invoked eagerly, and its return value is passed to the outer invokable object. If the bind subexpression has any placeholder arguments, they are shared with the outer bind .


在此使用mem_fn的唯一方式表達方式是通過它的結果爲bind爲傳送placeholders::_2bind(mem_fn(&foo::r), placeholders::_2)這是有效的,但當簡單的bind(&foo::r, placeholders::_2)就足夠了,這是一個不必要的步驟。因此產生函子最好的辦法是要麼你遞上聲明:

accumulate(cbegin(foos), cend(foos), 0, bind(plus<int>(), placeholders::_1, bind(&foo::r, placeholders::_2))) 

,或者通過使用拉姆達:

accumulate(cbegin(foos), cend(foos), 0, [](const int augend, const auto& addend) { return augend + addend.r(); }) 
2

好吧,很顯然,第二示例沒有提到placeholders::_2。當accumulate使用兩個參數調用仿函數時,第二個參數將被忽略,並且您的代碼嘗試將intmem_fn返回的內部類的實例相加。

我建議你放棄所有這些bind遊戲,並使用lambda:

accumulate(cbegin(foos), cend(foos), 0, 
    [](int val, foo* f) { return val + f->r(); }); 

更清楚什麼是怎麼回事。

相關問題