轻松选择节省空间
我认为这是一件有用的事情,但是完全专业化的工作比必要的要多一些(例如,变得operator=
正确)。
我在 Boost 邮件列表上发布了一种简化专业化任务的方法,尤其是当您只想专业化类模板的某些实例时。
http://boost.2283326.n4.nabble.com/optional-Specializing-optional-to-save-space-td4680362.html
我当前的界面涉及一种特殊的标签类型,用于“解锁”对特定功能的访问。我创造性地命名了这种类型optional_tag
。只能optional
构造一个optional_tag
。对于选择使用节省空间的表示的类型,它需要以下成员函数:
T(optional_tag)
构造一个未初始化的值
initialize(optional_tag, Args && ...)
当可能已经存在一个对象时构造一个对象
uninitialize(optional_tag)
销毁包含的对象
is_initialized(optional_tag)
检查对象当前是否处于初始化状态
通过始终需要 optional_tag 参数,我们不限制任何函数签名。这就是为什么,例如,我们不能operator bool()
用作测试,因为类型可能出于其他原因需要该运算符。
与其他一些可能的实现方法相比,它的一个优点是您可以使其与任何可以自然支持这种状态的类型一起使用。它没有添加任何要求,例如具有移动构造函数。
您可以在以下位置查看该想法的完整代码实现
https://bitbucket.org/davidstone/bounded_integer/src/8c5e7567f0d8b3a04cc98142060a020b58b2a00f/bounded_integer/detail/optional/optional.hpp?at=default&fileviewer=file-view-default
对于使用专业化的类:
https://bitbucket.org/davidstone/bounded_integer/src/8c5e7567f0d8b3a04cc98142060a020b58b2a00f/bounded_integer/detail/class.hpp?at=default&fileviewer=file-view-default
(第 220 至 242 行)
另一种方法
这与我之前的实现形成对比,后者需要用户专门化一个类模板。您可以在此处查看旧版本:
https://bitbucket.org/davidstone/bounded_integer/src/2defec41add2079ba023c2c6d118ed8a274423c8/bounded_integer/detail/optional/optional.hpp
和
https://bitbucket.org/davidstone/bounded_integer/src/2defec41add2079ba023c2c6d118ed8a274423c8/bounded_integer/detail/optional/specialization.hpp
这种方法的问题在于它对用户来说只是更多的工作。用户必须进入一个新的命名空间并专门化一个模板,而不是添加四个成员函数。
在实践中,所有特化都会有一个in_place_t
构造函数,将所有参数转发给底层类型。optional_tag
另一方面,该方法可以直接使用底层类型的构造函数。
在specializeoptional_storage
方法中,用户还有责任为值函数添加适当的引用限定重载。在该optional_tag
方法中,我们已经拥有价值,因此我们不必将其拉出。
optional_storage
还需要将标准化作为可选的两个辅助类的接口的一部分,用户应该只对其中一个进行专门化(有时将他们的专门化委托给另一个)。
this 和 compact_optional 的区别
compact_optional
是一种说法“将这个特殊的哨兵值视为不存在的类型,几乎就像一个 NaN”。它要求用户知道他们正在使用的类型有一些特殊的标记。一种易于optional
特化的说法是“我的类型不需要额外的空间来存储不存在的状态,但该状态不是正常值”。它不需要任何人了解优化来利用它;每个使用该类型的人都可以免费获得它。
未来
我的目标是首先将其放入 boost::optional 中,然后是 std::optional 提案的一部分。在此之前,您始终可以使用bounded::optional
,尽管它有一些其他(有意的)界面差异。