我正在研究基于libc ++的optional<T>
的{{1}}实现,它包含这样的联合:
optional
现在这里变得毛茸茸。我希望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
的实现都由另一个基类提供,名为let {'1}},另一个 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>
的定义,但派生的析构函数将隐式调用基类的析构函数,该析构函数被删除,因此无法编译。有没有“优雅”的方法来解决这个问题?我知道一个实用的解决方案,即爆炸bool参数:
__optional_destruct_base<T, false>
我对于以某种方式应用CRTP也有一个模糊的想法,但我还没弄清楚如何使这个工作。
任何不涉及__optional_destruct_base<T, false>::~__optional_destruct_base()
的想法?
答案 0 :(得分:0)
我对于以某种方式应用CRTP也有一个模糊的想法,但我还没有想出如何做到这一点。
我现在已经弄明白了!至少我相信这是行得通的。它通过了libc ++的测试套件。
无论我们放置联盟,默认情况下该类的析构函数都会被删除(如果T
不是简单的可破坏的话)。无论谁负责工会成员,那个班级必须也负责有条件的微不足道的析构函数。所以我们必须将联合直接保留在__optional_destruct_base<T>
内(因为那是我们选择负责析构函数的类)。
但是,我们可以成功地分离__engaged()
成员函数的责任!我们首先将析构函数的代码移回到具有union成员的类中:
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();
}
我们有它!我还不确定是否可以为具有不可破坏的基类的类编写析构函数...但是 可以解决我的限制问题具体案例,没有遇到模板专业化的组合爆炸,所有人都想成为&#34;最祖先的#34;。