Boost C++ 库

... 世界上最受推崇和设计精良的 C++ 库项目之一。 Herb SutterAndrei AlexandrescuC++ 编码标准

PrevUpHomeNext

第 43 章。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;

显然需要另一种方法。 典型的解决方案包括动态分配对象,然后通过一个公共基类型(通常是一个虚拟基类 [Hen01] 或更危险的 void*)对其进行操作。

但是,这种类型的解决方案极易出错,原因如下

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

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

解决方案:一个激励示例

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