This is another oddity in the new spec. the std::bind and lambda are not able to take std:move()'ed items. The crazy part is that the standards community went so far as to define a std::forward to achieve perfect forwarding and didn't even take the next logical step and create a perfect forwarding version of std::bind and lamba...
So I hacked up a perfect forwarding verion of std::bind. This version is the one parameter version of the perfect forwarding std::bind. Still working on the variadic template version for unlimited params.
#include <iostream> #include <memory> #include <utility> class MoveOnlyObj { public: MoveOnlyObj(int val) : val_(val) { std::cout << "MoveOnlyObj() - " << val_ << "\n"; } MoveOnlyObj(MoveOnlyObj&& obj) : val_(obj.val_) { std::cout << "MoveOnlyObj(&&) - " << val_ << "\n"; obj.val_ = 0; //0 it to make it very visable } ~MoveOnlyObj() { std::cout << "~MoveOnlyObj - " << val_ << "\n"; } private: friend std::ostream& operator<<(std::ostream& out, const MoveOnlyObj& o); MoveOnlyObj(MoveOnlyObj& obj); int val_; }; std::ostream& operator<<(std::ostream& out, const MoveOnlyObj& o) { out << o.val_; return out; } //lets start with the basic template <typename P> class MovableBinder1 { typedef void (*F)(P&&); private: F func_; P p0_; public: MovableBinder1(F func, P&& p) : func_(func), p0_(std::forward<P>(p)) { std::cout << "Moved" << p0_ << "\n"; } MovableBinder1(F func, P& p) : func_(func), p0_(p) { std::cout << "Copied" << p0_ << "\n"; } ~MovableBinder1() { std::cout << "~MovableBinder1\n"; } void operator()() { (*func_)(std::forward<P>(p0_)); } }; void test_func(int&& i) { std::cout << "test_func: " << i << "\n"; } void move_func(MoveOnlyObj&& i) { MoveOnlyObj taker(std::move(i)); std::cout << "move_func: " << taker << "\n"; } int main() { MovableBinder1<int> movable_binder_1_rvalue(&test_func, 3); movable_binder_1_rvalue(); int i=4; MovableBinder1<int> movable_binder_1_lvalue(&test_func, i); movable_binder_1_lvalue(); MoveOnlyObj m(5); MovableBinder1<MoveOnlyObj> movable_binder_move_only(&move_func, std::move(m)); movable_binder_move_only(); }
And the output looks like this:
Moved3 test_func: 3 Copied4 test_func: 4 MoveOnlyObj() - 5 MoveOnlyObj(&&) - 5 Moved5 MoveOnlyObj(&&) - 5 move_func: 5 ~MoveOnlyObj - 5 ~MovableBinder1 ~MoveOnlyObj - 0 ~MoveOnlyObj - 0 ~MovableBinder1 ~MovableBinder1
And here is the gripper... This one passes a thread in as the parameter..
#include <iostream> #include <memory> #include <utility> #include <thread> //lets start with the basic template <typename P> class MovableBinder1 { typedef void (*F)(P&&); private: F func_; P p0_; public: MovableBinder1(F func, P&& p) : func_(func), p0_(std::forward<P>(p)) {} MovableBinder1(F func, P& p) : func_(func), p0_(p) {} ~MovableBinder1() {} void operator()() { (*func_)(std::forward<P>(p0_)); } }; void thread_core() { std::this_thread::sleep_for(std::chrono::seconds(3)); } void join_thread(std::thread&& t) { std::cout << "Joining the thread....\n"; t.join(); } int main() { std::thread t(thread_core); MovableBinder1<std::thread> movable_binder_thread(&join_thread, std::move(t)); movable_binder_thread(); }
No comments:
Post a Comment