1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
/**
** \file misc/variant.hh
** \brief Interface of misc::variant.
**
** misc::variant is a wrapper over std::variant that adds
** conversion operators to the original standard variant class.
** misc::variant is used just like std::variant, and you
** won't be disturbed when using it.
**/
#pragma once
#include <variant>
namespace misc
{
// Defining some concepts sepecific to variants:
// Type T can be converted into another type in Ts,
// used to set the variant's value.
template <typename T, typename... Ts>
concept ContainsTypeSet =
std::disjunction<std::is_convertible<T, Ts>...>::value;
// A type in Ts can be converted into T, used to get the variant's value.
template <typename T, typename... Ts>
concept ContainsTypeGet =
std::disjunction<std::is_convertible<Ts, T>...>::value;
/// Type V is a visitor on each Ts.
template <typename V, typename... Ts>
concept Visits = std::conjunction<std::is_invocable<V, Ts>...>::value;
/// A wrapper over std::variant supporting conversion operators.
///
/// Constraints:
/// - No type may be const-qualified.
/// - Each type must be unique.
/// - The first type must be default constructible.
///
/// Proper declaration form:
/// misc::variant<T, T1, ..., Tn>
template <typename T, typename... Ts>
class variant : public std::variant<T, Ts...>
{
public:
/// The type of this variant.
using self_type = variant<T, Ts...>;
/// Super type.
using super_type = std::variant<T, Ts...>;
/// Constructors.
/// \{
variant() = default;
template <typename U>
requires ContainsTypeSet<U, T, Ts...>
variant(const U& rhs);
/// \}
template <typename U>
requires ContainsTypeSet<U, T, Ts...>
self_type& operator=(const U&);
/// \brief Convert this variant to a value of type \a U.
///
/// This conversion relies on std::get. In particular, if the
/// conversion fails, a std::bad_variant_access exception is thrown.
template <typename U>
requires ContainsTypeGet<U, T, Ts...>
operator U&();
/// Likewise, const version.
template <typename U>
requires ContainsTypeGet<U, T, Ts...>
operator const U&() const;
/** \brief Visit variants of this class.
** std::visit does not handle classes inheriting from std::variant, hence
** these wrappers.
** \{ */
template <typename V>
requires Visits<V, T, Ts...>
auto visit(V&& visitor) const;
template <typename V, class... Variants>
static auto visit(V&& visitor, Variants&&... vars);
/** \} */
};
// Here add variadic template recursion on std::get
template <typename T, typename... Ts>
std::ostream& operator<<(std::ostream& os, const variant<T, Ts...>& obj);
class PrintVisitor
{
public:
PrintVisitor(std::ostream& os)
: os_(os)
{}
template <typename T> std::ostream& operator()(const T& value) const;
private:
std::ostream& os_;
};
} // namespace misc
#include <misc/variant.hxx>
|