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