我实现了一个包装器,它允许我完美地将我的处理程序(在本例中是Widget对象)转发到可调用的中,然后我可以使用它作为信号处理程序。
我成功地将处理程序作为元组转发,因此当将lvalue ref作为参数传递以添加函数时,tuple存储对我的对象的引用。在这种情况下,一切看起来都很好。
但是,当我试图按值传递不可复制类的对象时,它会失败。原因是复制构造函数被隐式删除-当然,这是正确的,但我不能真正理解为什么它需要有副本ctor可用?这背后有什么理由吗?还是我的代码中有一个我没有注意到的bug?
使用clang 14编译,启用C++20
#include <boost/signals2/signal.hpp>
#include <tuple>
#include <boost/signals2/signal.hpp>
#include <iostream>
struct Widget
{
Widget() = default;
Widget(const Widget&) = delete;
Widget& operator=(const Widget&) = delete;
Widget(Widget&&) noexcept = default;
Widget& operator=(Widget&&) noexcept = default;
~Widget() noexcept = default;
void operator()()
{
std::cout << "Test\n";
}
};
struct SigWrapper
{
boost::signals2::signal<void()> sig;
template<class Handler>
void add(Handler&& handler)
{
//I need to wrap it here
auto wrapper = [handler_as_tuple = std::forward_as_tuple(std::forward<Handler>(handler))]() mutable {
//[...]
std::invoke(std::get<0>(handler_as_tuple));
};
sig.connect(std::move(wrapper));
}
void call()
{
sig();
}
};
int main()
{
auto w = SigWrapper{};
auto widget = Widget{};
w.add(widget); //ok: add as lvalue reference, will be wrapped into tuple that will hold ref to Widget
w.add(Widget{}); //error:
//copy constructor of '' is implicitly deleted because field '' has a deleted copy constructor
w.call();
}/opt/compiler-explorer/libs/boost_1_79_0/boost/signals2/detail/slot_template.hpp:160:26:错误:调用隐式删除的复制构造函数'(lambda在
:29:20)‘/opt/compiler-explorer/libs/boost_1_79_0/boost/signals2/detail/slot_template.hpp:85:9:= detail::get_invocable_slot(f,detail::tag_type(f));^ :34:17:注意:在函数模板专门化的实例化中,sig.connect(std::move(包装));^ :48:5:注意:在函数模板专门化的实例化中,“SigWrapper::add”w.add(Widget{});//error:^ :29:21:注意:“”的复制构造函数被隐式删除,因为“字段”具有已删除的复制构造函数自动包装器= 元组(std::forward(处理程序))可变的{^ /opt/compiler-explorer/gcc-11.2.0/lib/gcc/x86_64-linux-gnu/11.2.0/../../../../include/c++/11.2.0/tuple:744:17:注释:显式默认函数是在这里隐式删除了constexpr (constexpr&)= default;^ /opt/compiler-explorer/gcc-11.2.0/lib/gcc/x86_64-linux-gnu/11.2.0/../../../../include/c++/11.2.0/tuple:599:19:注意:' tuple‘的复制构造函数被隐式删除,因为基类' _Tuple_impl’有一个已删除的复制构造函数类元组: public _Tuple_impl^/_Tuple_impl/编译器-explorer/gcc-11.2.0/lib/gcc/x86_64-linux-gnu/11.2.0/../../../../include/c++/11.2.0/tuple:435:17:注意:显式默认函数在这里被隐式删除,_Tuple_impl(const _Tuple_impl&) = default;^ /opt/compiler-explorer/gcc-11.2.0/lib/gcc/x86_64-linux-gnu/11.2.0/../../../../include/c++/11.2.0/tuple:408:7:注意:“_Tuple_impl”的复制构造函数被隐式删除,因为基类“_Head_base”具有已删除的复制构造函数:_Head_base^/_Head_base/编译器-资源管理器/gcc-11.2.0/lib/gcc/x86_64-linux-gnu/11.2.0/../../../../include/c++/11.2.0/tuple:185:17:注意:显式默认函数在这里被隐式删除,_Head_base(const _Head_base&) = default;^ /opt/compiler-explorer/gcc-11.2.0/lib/gcc/x86_64-linux-gnu/11.2.0/../../../../include/c++/11.2.0/tuple:224:13:注意:“_Head_base”的复制构造函数被隐式删除,因为字段'_M_head_impl‘是rvalue引用类型'Widget &’_Head _M_head_impl;^ /opt/compiler-explorer/libs/boost_1_79_0/boost/function/function_template.hpp:1145:21:注:将参数'f‘传递给这里的参数operator=(函子f) ^
发布于 2022-07-01 10:51:38
Signals2是线程安全的.我认为可复制的要求就是这一结果的结果。例如,在不复制插槽功能的情况下,这种保证似乎很难实现:
注意,即使在断开连接之后,连接的相关插槽也可能仍在执行过程中。换句话说,断开连接不会阻止等待连接的相关插槽完成执行。这种情况可能发生在多线程环境中,如果断开与信号调用同时发生,或者在单线程环境中发生,如果插槽断开自己。
将共享对象转换为可复制对象的常用方法适用(例如使用std::shared_ptr)。
https://stackoverflow.com/questions/72827237
复制相似问题