Name Date Size #Lines LOC

..--

LICENSEH A D25-Apr-20251.4 KiB2522

LICENSE.spdxH A D25-Apr-2025257 87

LICENSE_1_0.txtH A D25-Apr-20251.3 KiB2420

README.mdH A D25-Apr-20257 KiB249177

README.md.licenseH A D25-Apr-202593 44

optional.hppH A D25-Apr-20251.6 KiB8054

recursive_wrapper.hppH A D25-Apr-20252.7 KiB12876

variant.hppH A D25-Apr-202532.6 KiB1,059866

variant_cast.hppH A D25-Apr-20251.9 KiB9174

variant_io.hppH A D25-Apr-20251,005 5134

variant_visitor.hppH A D25-Apr-20251 KiB4933

README.md

1# Mapbox Variant
2
3An header-only alternative to `boost::variant` for C++11 and C++14
4
5[![Build Status](https://secure.travis-ci.org/mapbox/variant.svg)](https://travis-ci.org/mapbox/variant)
6[![Build status](https://ci.appveyor.com/api/projects/status/v9tatx21j1k0fcgy)](https://ci.appveyor.com/project/Mapbox/variant)
7[![Coverage Status](https://coveralls.io/repos/mapbox/variant/badge.svg?branch=master&service=github)](https://coveralls.io/r/mapbox/variant?branch=master)
8
9## Introduction
10
11Variant's basic building blocks are:
12
13- `variant<Ts...>` - a type-safe representation for sum-types / discriminated unions
14- `recursive_wrapper<T>` - a helper type to represent recursive "tree-like" variants
15- `apply_visitor(visitor, myVariant)` - to invoke a custom visitor on the variant's underlying type
16- `get<T>()` - a function to directly unwrap a variant's underlying type
17- `.match([](Type){})` - a variant convenience member function taking an arbitrary number of lambdas creating a visitor behind the scenes and applying it to the variant
18
19### Basic Usage - HTTP API Example
20
21Suppose you want to represent a HTTP API response which is either a JSON result or an error:
22
23```c++
24struct Result {
25  Json object;
26};
27
28struct Error {
29  int32_t code;
30  string message;
31};
32```
33
34You can represent this at type level using a variant which is either an `Error` or a `Result`:
35
36```c++
37using Response = variant<Error, Result>;
38
39Response makeRequest() {
40  return Error{501, "Not Implemented"};
41}
42
43Response ret = makeRequest();
44```
45
46To see which type the `Response` holds you pattern match on the variant unwrapping the underlying value:
47
48```c++
49ret.match([] (Result r) { print(r.object); },
50          [] (Error e)  { print(e.message); });
51```
52
53Instead of using the variant's convenience `.match` pattern matching function you can create a type visitor functor and use `apply_visitor` manually:
54
55```c++
56struct ResponseVisitor {
57  void operator()(Result r) const {
58    print(r.object);
59  }
60
61  void operator()(Error e) const {
62    print(e.message);
63  }
64};
65
66ResponseVisitor visitor;
67apply_visitor(visitor, ret);
68```
69
70In both cases the compiler makes sure you handle all types the variant can represent at compile.
71
72### Recursive Variants - JSON Example
73
74[JSON](http://www.json.org/) consists of types `String`, `Number`, `True`, `False`, `Null`, `Array` and `Object`.
75
76```c++
77struct String { string value; };
78struct Number { double value; };
79struct True   { };
80struct False  { };
81struct Null   { };
82struct Array  { vector<?> values; };
83struct Object { unordered_map<string, ?> values; };
84```
85
86This works for primitive types but how do we represent recursive types such as `Array` which can hold multiple elements and `Array` itself, too?
87
88For these use cases Variant provides a `recursive_wrapper` helper type which lets you express recursive Variants.
89
90```c++
91struct String { string value; };
92struct Number { double value; };
93struct True   { };
94struct False  { };
95struct Null   { };
96
97// Forward declarations only
98struct Array;
99struct Object;
100
101using Value = variant<String, Number, True, False, Null, recursive_wrapper<Array>, recursive_wrapper<Object>>;
102
103struct Array {
104  vector<Value> values;
105};
106
107struct Object {
108  unordered_map<string, Value> values;
109};
110```
111
112For walking the JSON representation you can again either create a `JSONVisitor`:
113
114```c++
115struct JSONVisitor {
116
117  void operator()(Null) const {
118    print("null");
119  }
120
121  // same for all other JSON types
122};
123
124JSONVisitor visitor;
125apply_visitor(visitor, json);
126```
127
128Or use the convenience `.match` pattern matching function:
129
130```c++
131json.match([] (Null) { print("null"); },
132           ...);
133```
134
135To summarize: use `recursive_wrapper` to represent recursive "tree-like" representations:
136
137```c++
138struct Empty { };
139struct Node;
140
141using Tree = variant<Empty, recursive_wrapper<Node>>;
142
143struct Node {
144  uint64_t value;
145}
146```
147
148### Advanced Usage Tips
149
150Creating type aliases for variants is a great way to reduce repetition.
151Keep in mind those type aliases are not checked at type level, though.
152We recommend creating a new type for all but basic variant usage:
153
154```c++
155// the compiler can't tell the following two apart
156using APIResult = variant<Error, Result>;
157using FilesystemResult = variant<Error, Result>;
158
159// new type
160struct APIResult : variant<Error, Result> {
161  using Base = variant<Error, Result>;
162  using Base::Base;
163}
164```
165
166## Why use Mapbox Variant?
167
168Mapbox variant has the same speedy performance of `boost::variant` but is
169faster to compile, results in smaller binaries, and has no dependencies.
170
171For example on OS X 10.9 with clang++ and libc++:
172
173Test | Mapbox Variant | Boost Variant
174---- | -------------- | -------------
175Size of pre-compiled header (release / debug) | 2.8/2.8 MB         | 12/15 MB
176Size of simple program linking variant (release / debug)     | 8/24 K             | 12/40 K
177Time to compile header     | 185 ms             |  675 ms
178
179(Numbers from an older version of Mapbox variant.)
180
181## Goals
182
183Mapbox `variant` has been a very valuable, lightweight alternative for apps
184that can use c++11 or c++14 but that do not want a boost dependency.
185Mapbox `variant` has also been useful in apps that do depend on boost, like
186mapnik, to help (slightly) with compile times and to majorly lessen dependence
187on boost in core headers. The original goal and near term goal is to maintain
188external API compatibility with `boost::variant` such that Mapbox `variant`
189can be a "drop in". At the same time the goal is to stay minimal: Only
190implement the features that are actually needed in existing software. So being
191an "incomplete" implementation is just fine.
192
193Currently Mapbox variant doesn't try to be API compatible with the upcoming
194variant standard, because the standard is not finished and it would be too much
195work. But we'll revisit this decision in the future if needed.
196
197If Mapbox variant is not for you, have a look at [these other
198implementations](doc/other_implementations.md).
199
200Want to know more about the upcoming standard? Have a look at our
201[overview](doc/standards_effort.md).
202
203Most modern high-level languages provide ways to express sum types directly.
204If you're curious have a look at Haskell's pattern matching or Rust's and Swift's enums.
205
206## Depends
207
208- Compiler supporting `-std=c++11` or `-std=c++14`
209
210Tested with:
211
212- g++-4.7
213- g++-4.8
214- g++-4.9
215- g++-5.2
216- clang++-3.5
217- clang++-3.6
218- clang++-3.7
219- clang++-3.8
220- clang++-3.9
221- Visual Studio 2015
222
223## Unit Tests
224
225On Unix systems compile and run the unit tests with `make test`.
226
227On Windows run `scripts/build-local.bat`.
228
229## Limitations
230
231- The `variant` can not hold references (something like `variant<int&>` is
232  not possible). You might want to try `std::reference_wrapper` instead.
233
234## Deprecations
235
236- The included implementation of `optional` is deprecated and will be removed
237  in a future version. See [issue #64](https://github.com/mapbox/variant/issues/64).
238- Old versions of the code needed visitors to derive from `static_visitor`.
239  This is not needed any more and marked as deprecated. The `static_visitor`
240  class will be removed in future versions.
241
242## Benchmarks
243
244    make bench
245
246## Check object sizes
247
248    make sizes /path/to/boost/variant.hpp
249

README.md.license

1#
2# Copyright (c) MapBox 2016. All rights reserved.
3# SPDX-License-Identifier: BSD-3-Clause
4#