sof*_*mla 5 c++ templates bind variadic-templates c++11
我正在创建一个工作队列.作业将在线程A中创建,然后作业将发送到线程B,线程B将完成作业.作业完成后,作业将被发送回线程A.
#include <functional>
#include <iostream>
#include <memory>
using namespace std;
template<typename T, typename... Args>
class Job
{
public:
Job(std::weak_ptr<T> &&wp, std::function<void(const Args&...)> &&cb)
: _cb(std::move(cb)),
_cbWithArgs(),
_owner(std::move(wp)) {}
public:
template<typename... RfTs>
void bind(RfTs&&... args)
{
// bind will copy args for three times.
_cbWithArgs = std::bind(_cb, std::forward<RfTs>(args)...);
}
void fire()
{
auto sp = _owner.lock();
if (sp)
{
_cbWithArgs();
}
}
private:
std::function<void(const Args& ...)> _cb;
std::function<void()> _cbWithArgs;
std::weak_ptr<T> _owner;
};
struct Args
{
Args() = default;
Args(const Args &args)
{
cout << "Copied" << endl;
}
};
struct Foo
{
void show(const Args &)
{
cout << "Foo" << endl;
}
};
int main()
{
using namespace std::placeholders;
shared_ptr<Foo> sf (new Foo());
Args args;
// Let's say here thread A created the job.
Job<Foo, Args> job(sf, std::bind(&Foo::show, sf.get(), _1));
// Here thread B has finished the job and bind the result to the
// job.
job.bind(args);
// Here, thread A will check the result.
job.fire();
}
Run Code Online (Sandbox Code Playgroud)
以上代码编译和工作.但它给出了以下结果(g ++ 4.8.4&clang具有相同的结果):
Copied
Copied
Copied
Foo
Run Code Online (Sandbox Code Playgroud)
有三个副本!不能接受,我不知道我哪里做错了.为什么三份?我用谷歌搜索并从这里找到一个方法:https://stackoverflow.com/a/16868401,它只复制params一次.但它必须在构造函数中初始化bind函数.
谢谢,Piotr Skotnicki.不幸的是,我没有C++ 14编译器.所以,让我们让Args移动:
struct Args
{
Args() = default;
Args(const Args &args)
{
cout << "Copied" << endl;
}
Args(Args &&) = default;
Args& operator=(Args &&) = default;
};
Run Code Online (Sandbox Code Playgroud)
现在,它只复制一次:)
最后,我采用了这个主题的代码/sf/answers/1180770601/.我必须说,模板gen_seq是真正的ART.
第一个副本由它std::bind自己制作:
std::bind(_cb, std::forward<RfTs>(args)...)
Run Code Online (Sandbox Code Playgroud)
因为它需要存储其参数的衰变副本.
另外两个副本是由_cbWithArgs类型为std::function(第20.8.11.2.1节[func.wrap.func.con])的赋值产生的:
Run Code Online (Sandbox Code Playgroud)template<class F> function& operator=(F&& f);18 效果:
function(std::forward<F>(f)).swap(*this);
哪里:
Run Code Online (Sandbox Code Playgroud)template<class F> function(F f);9 [...]
*this目标是f初始化的副本std::move(f).
也就是说,构造函数的参数的一个副本,以及存储参数的另一个副本f.
由于Args是不可移动的类型,因此尝试从调用的结果移std::bind回到副本.
在您的代码中将作业执行结果存储在a中似乎不合理std::function.相反,您可以将这些值存储在元组中:
template <typename T, typename... Args>
class Job
{
public:
Job(std::weak_ptr<T> wp, std::function<void(const Args&...)> &&cb)
: _cb(std::move(cb)),
_owner(wp) {}
public:
template<typename... RfTs>
void bind(RfTs&&... args)
{
_args = std::forward_as_tuple(std::forward<RfTs>(args)...);
}
void fire()
{
auto sp = _owner.lock();
if (sp)
{
apply(std::index_sequence_for<Args...>{});
}
}
private:
template <std::size_t... Is>
void apply(std::index_sequence<Is...>)
{
_cb(std::get<Is>(_args)...);
}
std::function<void(const Args&...)> _cb;
std::weak_ptr<T> _owner;
std::tuple<Args...> _args;
};
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
271 次 |
| 最近记录: |