2021年了。现在回顾一下c++17标准中的std::variant/std::optional/std::any三个库是怎么实现的。
这三个库基本都是实现可选语义:
以上三种都可以看作是对union一种安全性改进。C/C++的union用法没有给程序员任何检查的手段,使得程序员心智负担加重。
另外这三个库的语义都很类似,但却分成了三个独立的库,且各自对同一种操作的写法也各不相同(丝毫没有减少心智负担):
std::optional<int> var1 = 7;
std::variant<int,string> var2 = 7;
std::any var3 = 7;
auto x1 = *var1 ; // 对 optional 解引用
auto x2 = std::get<int>(var2); // 像访问 tuple 一样访问 variant
auto x3 = std::any_cast<int>(var3); // 转换 any
三个库具体接口可以查阅cppreference。
一个安全类型的union:在union之上加了静态类型检查,有效阻止未定义行为。此外它还允许有默认的空状态。
采用TR1标准,即没有不定模板参数的variant签名。
template <
typename T0_
, BOOST_VARIANT_ENUM_SHIFTED_PARAMS(typename T)
>
class variant
{
/*...*/
which_t which_;
storage_t storage_;
}
另外std::variant令人繁琐的实现是:在不同类型variant之间的拷贝构造要考虑多种情景(主要是为了zero overhead)。于是这里涉及了重载的idom:boost选择的策略是类内用SFINEA方式实现多个重载函数。
在内存布局上和boost大同小异。实现上的不同在于重载的处理:STL则是通过继承类模板来实现静态时多态。
函数返回值可能不在返回类型的范围之内。例如float sqrt(float)函数。如果我们输入一个负数,此时返回值是无定义的。我们需要额外一个空类型,来区分这些无定义输入的返回状态(也可以是处理无法预定的返回类型)。
Empty_byte {};
template<typename T>
class aligned_storage
{
/*...*/
enum _storage<typename T> {
Empty_byte _empty;
T _value;
};
};
template<typename T>
class optional {
/*...*/
aligned_storage<T> storage;
};
和boost实现基本一致。
C++是一种静态强类型语言。有时候我们需要用到一些“弱”类型变量:它可以视作一个性的类型,当我们需要时,可以安全地把它cast到一个我们想要的类型。
在传统C++中,我们使用转换的方式有以下三种:
int a = static_cast<int>(1.0);
string s = lexical_cast<string>(a);
class a {
public:
a(){}
a(int) {}
a(const string&){}
}
class a {
public:
operator int(){}
operator char*(){}
}
我们可以利用std::any来统一类型的转换:
std::any a = string("1"); //转进
int i = std::any_cast<int>(a); //转出 i=1
实现一个模板构造函数。然后通过一个模板类来保存对应的值和类型(模拟虚表)。
class any {
public:
/*
...
*/
template<typename T>
any(T&& t) { _storage = new storage_t<std::decay_t<T>>(std::forward<T>(t))}
/*
...
*/
struct p{};
template<typename T> struct _storage_t:public p{ T t;};
p *storage;
};
STL则是使用void*类型实现:
在某些角度下,std::any的设计可以与std::function进行比较。标准std::function-type擦除策略的规范不同,它强调了保证nothrow移动操作的价值。虽然std::function对可应用小对象优化的包装函数对象类型几乎没有限制,但在本方案中,std::any将这些情况限制在包含对象的复制/移动操作不能引发异常的情况下。(n3804)
引用:
Variant: a type-safe union for C++17 (v8)
A proposal to add a utility class to represent optional objects (Revision 3)
Any Library Proposal (Revision 3)
From Mechanism to Method
MS-STL
GCC
BOOST