Boost C++ 库

……世界上最受推崇和设计精良的 C++ 库项目之一。 Herb SutterAndrei Alexandrescu,《C++编码规范

PrevUpHomeNext

第44章:Boost.Variant

Eric Friedman

Itay Maman

根据 Boost 软件许可证版本 1.0 分发。(参见附带文件 LICENSE_1_0.txt 或复制自 https://boost.ac.cn/LICENSE_1_0.txt

目录

引言
摘要
动机
教程
基本用法
高级主题
参考
概念
头文件 <boost/variant.hpp>
头文件 <boost/variant/variant_fwd.hpp>
头文件 <boost/variant/variant.hpp>
头文件 <boost/variant/recursive_variant.hpp>
头文件 <boost/variant/recursive_wrapper.hpp>
头文件 <boost/variant/apply_visitor.hpp>
头文件 <boost/variant/multivisitors.hpp>
头文件 <boost/variant/get.hpp>
头文件 <boost/variant/polymorphic_get.hpp>
头文件 <boost/variant/bad_visit.hpp>
头文件 <boost/variant/static_visitor.hpp>
头文件 <boost/variant/visitor_ptr.hpp>
设计概述
“永不为空”保证
其他说明
Boost.Variant 与 Boost.Any 的比较
可移植性
故障排除
致谢
参考文献

引言

摘要

variant 类模板是一个安全、通用、基于栈的辨别联合容器,提供了一种简单的解决方案,用于以统一的方式操作来自异构类型集的对象。标准容器如 std::vector 可以被认为是“多值,单类型”,而 variant 是“多类型,单值”。

boost::variant 的显著特性包括:

动机

问题

在 C++ 程序开发过程中,程序员经常需要以统一的方式操作几种不同的类型。实际上,C++ 通过其 union 关键字直接支持此类类型。

union { int i; double d; } u;
u.d = 3.14;
u.i = 3; // overwrites u.d (OK: u.d is a POD type)

然而,C++ 的 union 结构在面向对象环境中几乎毫无用处。该结构主要作为一种方法进入该语言,以保持与 C 的兼容性,C 只支持 POD(普通旧数据)类型,因此不接受表现出非平凡构造或析构的类型。

union {
  int i;
  std::string s; // illegal: std::string is not a POD type!
} u;

然后可以通过多态向下转换结构(例如,dynamic_castboost::any_cast 等)检索具体类型的对象。

然而,此类解决方案由于以下原因极易出错:

  • 向下转换错误无法在编译时检测到。 因此,不正确的向下转换结构用法会导致仅在运行时才能检测到的错误。
  • 可能会忽略新具体类型的添加。 如果向层次结构中添加新的具体类型,现有的向下转换代码将继续按原样工作,完全忽略新类型。因此,程序员必须手动查找和修改许多位置的代码,这通常会导致难以查找的运行时错误。

此外,即使正确实现,这些解决方案也往往由于使用了堆、虚拟函数调用和多态向下转换而导致相对较大的抽象开销。

解决方案:一个激励性示例

boost::variant 类模板以安全、直接和高效的方式解决了这些问题。以下示例演示了如何使用该类。

#include "boost/variant.hpp"
#include <iostream>

class my_visitor : public boost::static_visitor<int>
{
public:
    int operator()(int i) const
    {
        return i;
    }
    
    int operator()(const std::string & str) const
    {
        return str.length();
    }
};

int main()
{
    boost::variant< int, std::string > u("hello world");
    std::cout << u; // output: hello world

    int result = boost::apply_visitor( my_visitor(), u );
    std::cout << result; // output: 11 (i.e., length of "hello world")
}

PrevUpHomeNext