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