-
-
Notifications
You must be signed in to change notification settings - Fork 988
/
optional_reference.hpp
96 lines (81 loc) · 2.13 KB
/
optional_reference.hpp
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
/*
Copyright (C) 2021 by the Battle for Wesnoth Project https://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#pragma once
#include <functional>
#include <optional>
namespace utils
{
/**
* A simple wrapper class for optional reference types.
*
* Since std::optional (as of C++17 at least) does not support reference types (see [1]),
* the only way to use those is std::optional<std::reference_wrapper>. However, this makes
* the interace messy, as to access the referenced object you need an extra get() call to
* access the value stored in the reference wrapper.
*
* This does not rebind operator=() as boost::optional does. Instead, assigning a value
* to this object will simply change the object to which it points. To change the value
* of the referred to object, use value() or one of the other operators.
*
* [1] https://www.fluentcpp.com/2018/10/05/pros-cons-optional-references/
*/
template<typename T>
class optional_reference
{
public:
optional_reference() = default;
optional_reference(T& ref)
: opt_(ref)
{
}
optional_reference(std::nullopt_t)
: opt_()
{
}
T& value() const
{
#ifndef __APPLE__
return opt_.value().get();
#else
if(opt_) {
return opt_->get();
} else {
// We're going to drop this codepath once we can use optional::value anyway, but just
// noting we want this function to ultimately throw std::bad_optional_access.
throw std::runtime_error("Optional reference has no value");
}
#endif
}
optional_reference<T>& operator=(T& new_ref)
{
opt_ = new_ref;
return *this;
}
operator bool() const
{
return opt_.has_value();
}
T* ptr() const
{
return &value();
}
T* operator->() const
{
return ptr();
}
T& operator*() const
{
return value();
}
private:
std::optional<std::reference_wrapper<T>> opt_;
};
} // namespace utils