Apache Mesos
variant.hpp
Go to the documentation of this file.
1 // Licensed under the Apache License, Version 2.0 (the "License");
2 // you may not use this file except in compliance with the License.
3 // You may obtain a copy of the License at
4 //
5 // http://www.apache.org/licenses/LICENSE-2.0
6 //
7 // Unless required by applicable law or agreed to in writing, software
8 // distributed under the License is distributed on an "AS IS" BASIS,
9 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 // See the License for the specific language governing permissions and
11 // limitations under the License.
12 
13 #ifndef __STOUT_VARIANT_HPP__
14 #define __STOUT_VARIANT_HPP__
15 
16 #include <utility>
17 
18 #include <boost/variant.hpp>
19 
20 #include <stout/overload.hpp>
21 #include <stout/traits.hpp>
22 #include <stout/try.hpp>
23 
24 // A wrapper of `boost::variant` so that we can add our own
25 // functionality (e.g., `visit` via lambdas) as well as replace the
26 // implementation in the future (i.e., to use `mpark::variant` or
27 // `std::variant`).
28 //
29 // Example usage:
30 //
31 // Variant<int, bool> variant = "hello world";
32 //
33 // std::string type = variant.visit(
34 // [](int) { return "int"; },
35 // [](bool) { return "bool"; });
36 //
37 //
38 // *** IMPORANT IMPLEMENTATION DETAILS ***
39 //
40 // We do not inherit from `boost::variant` because it does not have a
41 // virtual destructor and therefore was not intended to be inherited
42 // from. This means that we need to provide our own `operator==`,
43 // `operator!=`, and `operator<<` for `std::ostream`. We found that
44 // when inheriting from `boost::variant` we needed to override
45 // `operator==` anyway.
46 template <typename T, typename... Ts>
47 class Variant // See above for why we don't inherit from `boost::variant`.
48 {
49 public:
50  // We provide a basic constuctor that forwards to `boost::variant`.
51  // Note that we needed to use SFINAE in order to keep the compiler
52  // from trying to use this constructor instead of the default copy
53  // constructor, move constructor, etc, as well as to keep the
54  // programmer from being able to construct an instance from
55  // `boost::variant` directly.
56  template <typename U,
57  typename Decayed = typename std::decay<U>::type,
58  typename = typename std::enable_if<
59  !std::is_same<Decayed, Variant>::value>::type,
60  typename = typename std::enable_if<
61  !std::is_same<Decayed, boost::variant<T, Ts...>>::value>::type>
62  Variant(U&& u) : variant(std::forward<U>(u)) {}
63 
64  template <typename... Fs>
65  auto visit(Fs&&... fs) const
66  -> decltype(
67  boost::apply_visitor(
68  overload(std::forward<Fs>(fs)...),
69  std::declval<boost::variant<T, Ts...>&>()))
70  {
71  return boost::apply_visitor(
72  overload(std::forward<Fs>(fs)...),
73  variant);
74  }
75 
76  template <typename... Fs>
77  auto visit(Fs&&... fs)
78  -> decltype(
79  boost::apply_visitor(
80  overload(std::forward<Fs>(fs)...),
81  std::declval<boost::variant<T, Ts...>&>()))
82  {
83  return boost::apply_visitor(
84  overload(std::forward<Fs>(fs)...),
85  variant);
86  }
87 
88  // Because we don't inherit from `boost::variant` we need to provide
89  // this operator ourselves, but note that even when we tried
90  // inheriting from `boost::variant` we still found that we needed to
91  // implement this operator in order to properly cast both operands
92  // to `boost::variant`.
93  bool operator==(const Variant& that) const
94  {
95  return variant == that.variant;
96  }
97 
98  bool operator!=(const Variant& that) const
99  {
100  return !(*this == that);
101  }
102 
103 private:
104  template <typename U, typename... Us>
105  friend std::ostream& operator<<(std::ostream&, const Variant<U, Us...>&);
106 
107  boost::variant<T, Ts...> variant;
108 };
109 
110 
111 template <typename T, typename... Ts>
112 std::ostream& operator<<(std::ostream& stream, const Variant<T, Ts...>& variant)
113 {
114  return stream << variant.variant;
115 }
116 
117 #endif // __STOUT_VARIANT_HPP__
auto visit(Fs &&...fs) const -> decltype(boost::apply_visitor(overload(std::forward< Fs >(fs)...), std::declval< boost::variant< T, Ts... > & >()))
Definition: variant.hpp:65
auto overload(Fs &&...fs) -> decltype(Overload< Fs... >(std::forward< Fs >(fs)...))
Definition: overload.hpp:80
Definition: interval.hpp:354
Definition: type_utils.hpp:619
bool operator==(const Variant &that) const
Definition: variant.hpp:93
Definition: fs.hpp:29
auto visit(Fs &&...fs) -> decltype(boost::apply_visitor(overload(std::forward< Fs >(fs)...), std::declval< boost::variant< T, Ts... > & >()))
Definition: variant.hpp:77
Definition: variant.hpp:47
Variant(U &&u)
Definition: variant.hpp:62
bool operator!=(const Variant &that) const
Definition: variant.hpp:98
friend std::ostream & operator<<(std::ostream &, const Variant< U, Us... > &)
Try< uint32_t > type(const std::string &path)