The Battle for Wesnoth  1.15.12+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>. 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 does not rebind operator=() as std::optional does. Instead, assigning a value
30  * to this object will simply change the object to which it points. To change the value
31  * of the referred to object, use value() or one of the other operators.
32  *
33  * [1] https://www.fluentcpp.com/2018/10/05/pros-cons-optional-references/
34  */
35 template<typename T>
37 {
38 public:
39  optional_reference() = default;
40 
42  : opt_(ref)
43  {
44  }
45 
46  optional_reference(std::nullopt_t)
47  : opt_()
48  {
49  }
50 
51  T& value() const
52  {
53 #ifndef __APPLE__
54  return opt_.value().get();
55 #else
56  if(opt_) {
57  return opt_->get();
58  } else {
59  // We're going to drop this codepath once we can use optional::value anyway, but just
60  // noting we want this function to ultimately throw std::bad_optional_access.
61  throw std::runtime_error("Optional reference has no value");
62  }
63 #endif
64  }
65 
67  {
68  opt_ = new_ref;
69  return *this;
70  }
71 
72  operator bool() const
73  {
74  return opt_.has_value();
75  }
76 
77  /** Returns a pointer to the referenced object or nullptr if no reference is held. */
78  T* ptr() const
79  {
80  if(opt_) {
81  return &value();
82  } else {
83  return nullptr;
84  }
85  }
86 
87  T* operator->() const
88  {
89  return &value();
90  }
91 
92  T& operator*() const
93  {
94  return value();
95  }
96 
97 private:
98  std::optional<std::reference_wrapper<T>> opt_;
99 };
100 
101 } // 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)