摧毁一个不可破坏的基类?
Destroy a non-destructible base class?
我正在基于 libc++ 的optional
进行optional<T>
的实现,其中包含如下联合:
template<class T, bool = is_trivially_destructible_v<T>>
struct __optional_destruct_base {
union {
char __null_state_;
T __val_;
};
// no destructor needed; this class is trivially destructible
};
template<class T>
struct __optional_destruct_base<T, false> {
union {
char __null_state_;
T __val_;
};
// destructor must be user-provided because the union's destructor is deleted
~__optional_destruct_base() {
if (this->__engaged()) __val_.~T();
}
};
template<class T>
class optional : private __optional_destruct_base<T> { ... };
现在这就是它变得毛茸茸的地方。我希望union
成员和this->__engaged()
的实现都由另一个基类提供,称为__optional_storage_base<T>
,以及另一个bool
模板非类型参数。我尝试这样做:
template<class T, bool = is_foo_v<T>>
struct __optional_storage_base {
union { char __null_state_; T __val_; };
bool __engaged() const { puts("foo"); return false; }
};
template<class T>
struct __optional_storage_base<T, false> {
union { char __null_state_; T __val_; };
bool __engaged() const { puts("bar"); return false; }
};
template<class T, bool = is_trivially_destructible_v<T>>
struct __optional_destruct_base : __optional_storage_base<T>
{
};
template<class T>
struct __optional_destruct_base<T, false> : __optional_storage_base<T>
{
~__optional_destruct_base() {
if (this->__engaged()) __val_.~T();
}
};
template<class T>
class optional : private __optional_destruct_base<T> { ... };
但这会导致在实例化optional<some_T_which_is_not_trivially_destructible>
时编译器错误,因为:
T
不是微不足道的可破坏的,- 因此,
__optional_storage_base<T>
的工会成员有一个隐式删除的析构函数, - 因此
__optional_storage_base<T>
本身有一个已删除的析构函数, - 因此
__optional_destruct_base<T, false>
有一个基类,其析构函数被删除; - 虽然我提供了
__optional_destruct_base<T, false>::~__optional_destruct_base()
的定义,但派生析构函数将隐式调用基类的析构函数,该析构函数被删除,因此无法编译。
有没有"优雅"的方法可以解决这个问题? 我知道一个实用的解决方案,那就是分解布尔参数:
template<class T, bool = is_trivially_destructible_v<T>, bool = is_foo_v<T>>
struct __optional_combinatorial_explosion_base { ... };
template<class T>
struct __optional_combinatorial_explosion_base<T, false, true> { ... };
template<class T>
struct __optional_combinatorial_explosion_base<T, true, false> { ... };
template<class T>
struct __optional_combinatorial_explosion_base<T, true, true> { ... };
我也有一个关于以某种方式应用 CRTP 的模糊想法,但我还没有弄清楚如何使其工作。
任何不涉及__optional_combinatorial_explosion_base
的想法?
我也有一个关于以某种方式应用 CRTP 的模糊想法,但我还没有弄清楚如何做到这一点。
我现在已经想通了!至少我相信这是有效的。它通过了libc++的测试套件。
无论我们把联合放在哪里,默认情况下,该类的析构函数都将被删除(如果T
不是可破坏的)。无论谁负责工会成员,该阶级也必须负责有条件的琐碎破坏者。因此,我们必须将联合直接保留在__optional_destruct_base<T>
内部(因为这是我们选择负责析构函数的类)。
但是,我们可以成功地拆分__engaged()
成员功能的责任!我们首先将析构函数的代码移回具有联合成员的类中:
template<class T, bool = is_trivially_destructible_v<T>>
struct __optional_destruct_base {
union { char __null_state_; T __val_; };
};
template<class T>
struct __optional_destruct_base<T, false> {
union { char __null_state_; T __val_; };
~__optional_destruct_base() {
if (this->__engaged()) __val_.~T();
}
};
template<class T, bool = is_foo_v<T>>
struct __optional_engaged_base : __optional_destruct_base <T>
{
bool __engaged() const { puts("foo"); return false; }
};
template<class T>
struct __optional_engaged_base<T, false> : __optional_destruct_base<T>
{
bool __engaged() const { puts("bar"); return false; }
};
template<class T>
class optional : private __optional_engaged_base<T> { ... };
这几乎可以编译,除了析构函数中试图调用__engaged()
的行:
~__optional_destruct_base() {
if (this->__engaged()) __val_.~T(); // oops!
}
此处,基类尝试调用仅在派生类中实现的方法。所以我们应用CRTP!除了我们甚至不需要传入模板参数,因为我们知道谁将提供__engaged
方法。
~__optional_destruct_base() {
auto *__self = static_cast<__optional_engaged_base<T> *>(this);
if (__self->__engaged()) __val_.~T();
}
我们有它!我仍然不确定是否可以为具有不可破坏基类的类编写析构函数......但是在我的特定情况下,可以解决这一限制,而不会遇到模板专业化的组合爆炸,这些模板专业化都希望成为"最祖先"。
- 在模板基类中为继承类中的可选重写生成虚拟方法
- 使(虚拟)函数在大多数派生类中无法访问中间基类中可访问,定义良好?
- 将空基类优化对象强制转换为另一种类型是否会破坏严格的别名?
- 摧毁一个不可破坏的基类?
- 如何使用 CRTP 创建具有基类的可选模板参数
- 从特定专业化继承时可访问的模板基类?
- 继承:派生类的基类属性可访问性
- 可视化C++对象被上投射到基类;无法调用派生方法
- 在不破坏封装的情况下访问基类元素
- 有没有办法破坏然后移动构造一个多态基类
- 为什么我会收到错误'A<int>'不是基类的基类的可访问'S<int>'基?
- 可视化 当基类和子类具有相同的对象名称但类型不同时,如何访问子类的数据成员。在C++
- 如何使用gdb破坏基类的构造函数
- 带有纯虚拟回调的线程化基类,在破坏c++时停止
- 虚拟继承是否强制基类默认为可构造的
- 将成员函数从基类移动到派生类会无缘无故地破坏程序
- c++中私有基类的可访问性
- "virtual"关键字在C++的基类中是可选的吗?
- 可扩展的基类方法
- 用于智能指针(intrusive_ptr)的抽象基类-处理继承性、多态性、可克隆性和从工厂返回的方法