我想构建一个简单的boost::lockfree::queue
函数,它们不带任何参数并且不返回任何值。
boost::lockfree::queue
似乎要求项目类型可以轻易分配和销毁,boost::function<void ()>
很遗憾不满足这些要求。
本着https://stackoverflow.com/a/21406186/393756的精神,我现在试图通过boost::lockfree::queue
普通函数指针实现这一点:
boost::lockfree::queue<void (*)()> queue;
我可以将boost::function<void ()>
推入此队列吗?如果是,怎么做?
答案 0 :(得分:1)
我可以将
boost::function<void()>
推入此队列吗?
不直接,因为boost::function<void()>
是一个重量级拥有类型擦除的包装器,它不能隐式转换为函数指针并且还存储一些数据。
如果你需要一个简单可分配的,可以引用到任何函数对象的简单可破坏类型,你可以实现一个function_view
类,它指向某个函数对象而不拥有它。如果你小心一生,并保证function_view
总是指向&#34;活着的对象&#34;您可以安全地将其实例存储在队列中。
从概念上讲,function_view
是一对指针。我在我的"passing functions to functions"文章中有一个实现,我将在下面粘贴:
template <typename TReturn, typename... TArgs>
class function_view<TReturn(TArgs...)> final
{
private:
using signature_type = TReturn(void*, TArgs...);
void* _ptr;
TReturn (*_erased_fn)(void*, TArgs...);
public:
template <typename T, typename = std::enable_if_t<
std::is_callable<T&(TArgs...)>{} &&
!std::is_same<std::decay_t<T>, function_view>{}>>
function_view(T&& x) noexcept : _ptr{(void*)std::addressof(x)}
{
_erased_fn = [](void* ptr, TArgs... xs) -> TReturn {
return (*reinterpret_cast<std::add_pointer_t<T>>(ptr))(
std::forward<TArgs>(xs)...);
};
}
decltype(auto) operator()(TArgs... xs) const
noexcept(noexcept(_erased_fn(_ptr, std::forward<TArgs>(xs)...)))
{
return _erased_fn(_ptr, std::forward<TArgs>(xs)...);
}
};
此课程通过以下测试:
using type = function_view<void()>;
static_assert(is_trivially_assignable<type, type>{});
static_assert(is_trivially_destructible<type>{});
答案 1 :(得分:1)
不,但您可以使用动态内存分配+类型擦除:
struct callback_back{
virtual void execute() = 0;
~callback_base() = default;
};
template<class F>
class callback{
private:
F m_function;
public:
callback(F&& function) : m_function(std::forward<F>(function)){}
virtual void execute() {
m_function();
}
}
template<class F>
std::unique_ptr<callback_base> make_callback(F&& f){
return std::unique_ptr<callback_base>(
new callback<F>(std::forward<F>(f));
);
}
使用callback_base
作为noexcept-movable类型(又名boost::lockfree::queue<std::unique_ptr<callback_base>>
)。
答案 2 :(得分:0)
到目前为止,我发现的唯一方法是制作函数对象的原始指针
boost::lockfree::queue<std::function<void(void)> *> tasks_; // the queue
// let f = stack allocated std::function<T(T)> instance
tasks_.push(new std::function<void(void)>(f));
// pop
std::function<void(void)> * f;
tasks_.pop(f);
// execute in try/catch make sure to delete in case of exception?
(*f)();
// you should delete f here if you are done with it
// in the destructor of the class that owns tasks_ you should delete the remaining std::function instances
这里的挑战是出于安全考虑,何时删除该实例