-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathebo_wrapper.h
107 lines (86 loc) · 3.78 KB
/
ebo_wrapper.h
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
97
98
99
100
101
102
103
104
105
106
#ifndef COOL_EBO_WRAPPER_H_
#define COOL_EBO_WRAPPER_H_
#include <functional>
#include <type_traits>
#include <utility>
///////////////////////////////////////////////////////////////////////////////
// ebo_wrapper
//
// ebo_wrapper is a wrapper which uses private inheritance to take advantage
// of EBO for non-final classes and aggregation everywhere else. The
// key benefit is to provide a consistent interface regardless of which
// implementation is used.
//
// The intended use is to privately inherit from ebo_wrapper<T> and call
// ref() to get a reference to the held T.
//
// Like reference_wrapper, there is also an implicit conversion to
// (const_)reference and a Callable interface.
//
// cool::detail::ebo_wrapper takes two template parameters, the second of
// which should always be void and is used to SFINAE private inheritance vs.
// aggregation implementations.
//
// cool::ebo_wrapper only takes one template parameter.
//
///////////////////////////////////////////////////////////////////////////////
namespace cool
{
namespace detail
{
template<typename T, typename = void>
struct ebo_wrapper
{
using value_type = T;
using reference = T &;
using const_reference = T const&;
template<typename... Us, typename = std::enable_if_t<std::is_constructible_v<T, Us...>>>
constexpr ebo_wrapper(Us&&... us)
noexcept(noexcept(T(std::forward<Us>(us)...)))
: m_t(std::forward<Us>(us)...)
{}
constexpr reference ref() noexcept { return m_t; }
constexpr const_reference ref() const noexcept { return m_t; }
constexpr operator reference() noexcept { return m_t; }
constexpr operator const_reference() const noexcept { return m_t; }
template<typename... ArgTypes>
auto // std::invoke_result_t<T&, ArgTypes...>
operator()(ArgTypes&&... args)
{ return std::invoke(ref(), std::forward<ArgTypes>(args)...); }
template<typename... ArgTypes>
auto // std::invoke_result_t<T const&, ArgTypes...>
operator()(ArgTypes&&... args) const
{ return std::invoke(ref(), std::forward<ArgTypes>(args)...); }
private:
T m_t;
};
template<typename T>
struct ebo_wrapper<T, std::enable_if_t<std::is_empty_v<T> && !std::is_final_v<T>>>
: private T
{
using value_type = T;
using reference = T &;
using const_reference = T const&;
template<typename... Us, typename = std::enable_if_t<std::is_constructible_v<T, Us...>>>
constexpr ebo_wrapper(Us&&... us)
noexcept(noexcept(T(std::forward<Us>(us)...)))
: T(std::forward<Us>(us)...)
{}
constexpr reference ref() noexcept { return *this; }
constexpr const_reference ref() const noexcept { return *this; }
constexpr operator reference() noexcept { return *this; }
constexpr operator const_reference() const noexcept { return *this; }
template<typename... ArgTypes>
auto // std::invoke_result_t<T&, ArgTypes...>
operator()(ArgTypes&&... args)
{ return std::invoke(ref(), std::forward<ArgTypes>(args)...); }
template<typename... ArgTypes>
auto // std::invoke_result_t<T const&, ArgTypes...>
operator()(ArgTypes&&... args) const
{ return std::invoke(ref(), std::forward<ArgTypes>(args)...); }
};
} // detail namespace
template<typename T>
using ebo_wrapper = detail::ebo_wrapper<T>;
} // cool namespace
#endif /* COOL_EBO_WRAPPER_H_ */