The Battle for Wesnoth  1.17.0-dev
optional_reference.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2021 by the Battle for Wesnoth Project https://www.wesnoth.org/
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or
7  (at your option) any later version.
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY.
10 
11  See the COPYING file for more details.
12 */
13 
14 #pragma once
15 
16 #include <functional>
17 #include <optional>
18 
19 namespace utils
20 {
21 /**
22  * A simple wrapper class for optional reference types.
23  *
24  * Since std::optional (as of C++17 at least) does not support reference types (see [1]),
25  * the only way to use those is std::optional<std::reference_wrapper<T>>. However, this makes
26  * the interace messy, as to access the referenced object you need an extra get() call to
27  * access the value stored in the reference wrapper.
28  *
29  * This rebinds operator=() as boost::optional does. Assigning a value to this wrapper will
30  * simply change the object to which it points instead of assigning a value to the referenced
31  * object. To change the value of the referenced object, perform an assignment on value()
32  * or operator*.
33  *
34  * [1] https://www.fluentcpp.com/2018/10/05/pros-cons-optional-references/
35  */
36 template<typename T>
38 {
39 public:
40  optional_reference() = default;
41 
43  : opt_(ref)
44  {
45  }
46 
47  optional_reference(std::nullopt_t)
48  : opt_()
49  {
50  }
51 
52  T& value() const
53  {
54 #ifndef __APPLE__
55  return opt_.value().get();
56 #else
57  if(opt_) {
58  return opt_->get();
59  } else {
60  // We're going to drop this codepath once we can use optional::value anyway, but just
61  // noting we want this function to ultimately throw std::bad_optional_access.
62  throw std::runtime_error("Optional reference has no value");
63  }
64 #endif
65  }
66 
68  {
69  opt_ = new_ref;
70  return *this;
71  }
72 
73  operator bool() const
74  {
75  return opt_.has_value();
76  }
77 
78  /** Returns a pointer to the referenced object or nullptr if no reference is held. */
79  T* ptr() const
80  {
81  if(opt_) {
82  return &value();
83  } else {
84  return nullptr;
85  }
86  }
87 
88  T* operator->() const
89  {
90  return &value();
91  }
92 
93  T& operator*() const
94  {
95  return value();
96  }
97 
98 private:
99  std::optional<std::reference_wrapper<T>> opt_;
100 };
101 
102 } // namespace utils
std::optional< std::reference_wrapper< T > > opt_
T * ptr() const
Returns a pointer to the referenced object or nullptr if no reference is held.
A simple wrapper class for optional reference types.
optional_reference< T > & operator=(T &new_ref)