├── .gitattributes ├── test ├── catch_main.cpp └── test.cpp ├── .gitignore ├── CMakeLists.txt ├── LICENSE.txt ├── README.md └── include └── raspberry └── raspberry.hpp /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /test/catch_main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #define CATCH_CONFIG_MAIN 3 | #include "catch.hpp" 4 | 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /* 2 | !include 3 | !test 4 | !.gitignore 5 | !CMakeLists.txt 6 | !README.md 7 | !LICENSE.txt 8 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.0) 2 | project(Raspberry) 3 | 4 | file(GLOB_RECURSE raspberry_SOURCES include/raspberry/*) 5 | add_library(raspberry INTERFACE) 6 | set_property(TARGET raspberry PROPERTY INTERFACE_SOURCES ${raspberry_SOURCES}) 7 | target_include_directories(raspberry INTERFACE include) 8 | 9 | file(GLOB_RECURSE raspberry_test_SOURCES test/*) 10 | add_executable(test_raspberry EXCLUDE_FROM_ALL ${raspberry_test_SOURCES}) 11 | set_property(TARGET test_raspberry PROPERTY CXX_STANDARD 14) 12 | target_link_libraries(test_raspberry raspberry) 13 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Jeramy Harrison 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Raspberry 2 | === 3 | 4 | Raspberry is a lightweight C++ type erasure library. 5 | 6 | The particular method of type erasure used by Raspberry is very simple. 7 | 8 | Take a look at this typical inheritance example: 9 | 10 | ```C++ 11 | struct Animal { 12 | virtual void speak() = 0; 13 | virtual ~Animal() = 0; 14 | }; 15 | inline Animal::~Animal() = default; 16 | 17 | struct Cat final : Animal { 18 | virtual void speak() override { 19 | std::cout << "Meow!" << std::endl; 20 | } 21 | }; 22 | 23 | void listen() { 24 | std::unique_ptr animal = std::make_unique(); 25 | animal->speak(); 26 | } 27 | ``` 28 | 29 | And the equivalent example using Raspberry: 30 | 31 | ```C++ 32 | RASPBERRY_DECL_METHOD(SpeakConcept, speak); 33 | 34 | using Animal = raspberry::Any>; 35 | 36 | struct Cat { 37 | void speak() { 38 | std::cout << "Meow!" << std::endl; 39 | } 40 | }; 41 | 42 | void listen() { 43 | Animal animal = Cat{}; 44 | animal.speak(); 45 | } 46 | ``` 47 | 48 | These two examples are of equal efficiency. 49 | They perform the same number of allocations, 50 | use the same amount of memory, 51 | execute in the same amount of time, 52 | and result in the same assembly code (tested with GCC 5.1). 53 | 54 | Usage 55 | === 56 | 57 | Everything you need is in the single, 160-line header file, `raspberry/raspberry.hpp`. 58 | 59 | Declaring Concepts 60 | --- 61 | 62 | Right now, Raspberry only supports class method concepts. 63 | 64 | They are declared like this: 65 | 66 | ```C++ 67 | RASPBERRY_DECL_METHOD(FuncConcept, func); 68 | ``` 69 | 70 | Declaring Erasure Types 71 | --- 72 | 73 | Raspberry's erasure objects are called `Any`. 74 | Any object can be stored in an `Any<>`. 75 | This is, of course, useless. 76 | 77 | We can use previously declared Raspberry concepts to add methods to our `Any`: 78 | 79 | ```C++ 80 | RASPBERRY_DECL_METHOD(FuncConcept, func); 81 | 82 | using AnyFunc = raspberry::Any< FuncConcept >; 83 | ``` 84 | 85 | Notice how we give the concept the type of the method to create. 86 | This allows an `Any` to have several overloads of the same method. 87 | 88 | Creating Erasures from Objects 89 | --- 90 | 91 | Any class type that contains the required methods can be converted into an `Any`. 92 | If a class type is missing any of the required methods, compilation will fail. 93 | 94 | ```C++ 95 | RASPBERRY_DECL_METHOD(FuncConcept, func); 96 | 97 | using AnyFunc = raspberry::Any< FuncConcept >; 98 | 99 | struct SomeFunc { 100 | void func() { 101 | std::cout << "func() called!" << std::endl; 102 | } 103 | }; 104 | 105 | void test(AnyFunc a) { 106 | a.func(); 107 | } 108 | 109 | int main() { 110 | SomeFunc sf; 111 | test(sf); 112 | } 113 | ``` 114 | 115 | Creating Erasures from References 116 | --- 117 | 118 | `Any` has special semantics for `std::reference_wrapper` types. 119 | The underlying reference is extracted from the wrapper, 120 | and stored in the erasure. 121 | 122 | This allows `Any` to safely store references. 123 | 124 | ```C++ 125 | void test(AnyFunc a) { 126 | a.func(); 127 | } 128 | 129 | int main() { 130 | SomeFunc sf; 131 | test( std::ref(sf) ); 132 | } 133 | ``` 134 | 135 | Multiple Concepts, Const-qualifiers, and Overloading 136 | --- 137 | 138 | `Any` supports any number of concepts, including zero. 139 | Methods may be `const`, and may be overloaded. 140 | 141 | As expected, `const` methods may be called on a non-const object. 142 | 143 | ```C++ 144 | RASPBERRY_DECL_METHOD(GetStringConcept, get_string); 145 | RASPBERRY_DECL_METHOD(SetStringConcept, set_string); 146 | 147 | using AnyStringHolder = raspberry::Any< 148 | GetStringConcept, 149 | SetStringConcept, 150 | SetStringConcept 151 | >; 152 | ``` 153 | 154 | Method Return Value Implicit Conversions 155 | --- 156 | 157 | The return type specified in a concept may be different from the erased method's actual return type, 158 | only if the actual return type can be implicitly converted to the concept's return type. 159 | 160 | ```C++ 161 | RASPBERRY_DECL_METHOD(IdentityConcept, identity); 162 | 163 | using AnyIdentity = raspberry::Any< IdentityConcept >; 164 | 165 | struct SomeIdentity { 166 | double identity(double d) { return d; } 167 | }; 168 | 169 | void test() { 170 | SomeIdentity s; 171 | assert( s.identity(7.42) == 7.42 ); 172 | 173 | AnyIdentity a = s; 174 | 175 | assert( a.identity(7.42) == 7 ); 176 | } 177 | ``` 178 | 179 | Please be careful with this feature, as it can lead to data loss (e.g. casting a `double` to an `int`). 180 | 181 | License 182 | === 183 | 184 | MIT. See `LICENSE.txt`. 185 | -------------------------------------------------------------------------------- /test/test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "catch.hpp" 3 | 4 | #include 5 | 6 | #include 7 | 8 | RASPBERRY_DECL_METHOD(FuncConcept, func); 9 | RASPBERRY_DECL_METHOD(SquareConcept, square); 10 | 11 | using AnyFunc = raspberry::Any,SquareConcept>; 12 | 13 | struct SomeFunc { 14 | int func() const { 15 | return 42; 16 | } 17 | 18 | float square(float x) { 19 | return x*x; 20 | } 21 | }; 22 | 23 | TEST_CASE("Objects can be stored in Any", "[raspberry]") { 24 | AnyFunc f = SomeFunc{}; 25 | 26 | REQUIRE(f.func() == 42); 27 | REQUIRE(f.square(12) == 144); 28 | } 29 | 30 | struct negative_test_assign { 31 | template 32 | static decltype( AF(std::declval()), bool{} ) test(int) { return false; } 33 | 34 | template 35 | static bool test(long) { return true; } 36 | }; 37 | 38 | TEST_CASE("Any cannot be stored in Any or copied", "[raspberry]") { 39 | REQUIRE(negative_test_assign::test(int{})); 40 | } 41 | 42 | RASPBERRY_DECL_METHOD(RefDetectConcept, ref_detect); 43 | 44 | using AnyRefDetector = raspberry::Any>; 45 | 46 | struct RefDetector { 47 | int value = 0; 48 | 49 | void ref_detect(int x) { 50 | value = x; 51 | } 52 | }; 53 | 54 | TEST_CASE("Objects are copied by default", "[raspberry]") { 55 | RefDetector rd; 56 | REQUIRE(rd.value == 0); 57 | 58 | AnyRefDetector ard = rd; 59 | REQUIRE(rd.value == 0); 60 | 61 | ard.ref_detect(42); 62 | REQUIRE(rd.value == 0); 63 | } 64 | 65 | TEST_CASE("std::reference_wrapper is used to capture by reference", "[raspberry]") { 66 | RefDetector rd; 67 | REQUIRE(rd.value == 0); 68 | 69 | AnyRefDetector ard = std::ref(rd); 70 | REQUIRE(rd.value == 0); 71 | 72 | ard.ref_detect(42); 73 | REQUIRE(rd.value == 42); 74 | } 75 | 76 | RASPBERRY_DECL_METHOD(SetStringConcept, set_string); 77 | 78 | using AnySetString = raspberry::Any< 79 | SetStringConcept< void(const std::string&) >, 80 | SetStringConcept< void(const char*) > 81 | >; 82 | 83 | struct StringSetter { 84 | std::string value; 85 | 86 | void set_string(const std::string& s) { 87 | value = s; 88 | } 89 | 90 | void set_string(const char* s) { 91 | value = s; 92 | } 93 | }; 94 | 95 | TEST_CASE("Methods can be overloaded", "[raspberry]") { 96 | StringSetter s; 97 | AnySetString a = std::ref(s); 98 | 99 | a.set_string("char[]"); 100 | REQUIRE(s.value == "char[]"); 101 | 102 | a.set_string(std::string("std::string")); 103 | REQUIRE(s.value == "std::string"); 104 | 105 | } 106 | 107 | RASPBERRY_DECL_METHOD(MaybeConstGetter, get); 108 | 109 | using AnyMaybeConstGetter = raspberry::Any< 110 | MaybeConstGetter< int&() >, 111 | MaybeConstGetter< const int&() const > 112 | >; 113 | 114 | struct SomeMaybeConstGetter { 115 | int value; 116 | int& get() { return value; } 117 | const int& get() const { return value; } 118 | }; 119 | 120 | TEST_CASE("Const and non-const overloads can coexist", "[raspberry]") { 121 | SomeMaybeConstGetter s; 122 | AnyMaybeConstGetter a = std::ref(s); 123 | 124 | s.value = 7; 125 | REQUIRE(s.value == 7); 126 | 127 | a.get() = 42; 128 | REQUIRE(s.value == 42); 129 | 130 | const auto& ac = a; 131 | REQUIRE(ac.get() == 42); 132 | REQUIRE(std::is_const>::value); 133 | } 134 | 135 | using AnyMaybeConstGetterReversed = raspberry::Any< 136 | MaybeConstGetter< const int&() const >, 137 | MaybeConstGetter< int&() > 138 | >; 139 | 140 | TEST_CASE("Const and non-const overloads can come in any order", "[raspberry]") { 141 | SomeMaybeConstGetter s; 142 | AnyMaybeConstGetterReversed a = std::ref(s); 143 | 144 | s.value = 7; 145 | REQUIRE(s.value == 7); 146 | 147 | a.get() = 42; 148 | REQUIRE(s.value == 42); 149 | 150 | const auto& ac = a; 151 | REQUIRE(ac.get() == 42); 152 | REQUIRE(std::is_const>::value); 153 | } 154 | 155 | RASPBERRY_DECL_METHOD(ConstTester, c_func); 156 | 157 | using AnyConstTester = raspberry::Any< ConstTester< void() > >; 158 | 159 | struct SomeConstTester { 160 | void c_func() const {} 161 | }; 162 | 163 | TEST_CASE("Const methods can be called from non-const concepts", "[raspberry]") { 164 | AnyConstTester ac = SomeConstTester{}; 165 | ac.c_func(); 166 | REQUIRE(true); 167 | } 168 | 169 | RASPBERRY_DECL_METHOD(ConversionTester, test); 170 | 171 | using AnyConversionTester = raspberry::Any< ConversionTester< int(double) > >; 172 | 173 | struct SomeConversionTester { 174 | double test(double d) const { return d; } 175 | }; 176 | 177 | TEST_CASE("Method return values follow implicit conversion through concepts", "[raspberry]") { 178 | SomeConversionTester s; 179 | double d = 7.42; 180 | REQUIRE(s.test(d) == 7.42); 181 | 182 | AnyConversionTester a = s; 183 | REQUIRE(a.test(d) == 7); 184 | } 185 | 186 | struct RecAnyFunc final : raspberry::Any< 187 | FuncConcept 188 | > { using Any::Any; }; 189 | 190 | struct RecAnyTester { 191 | int x; 192 | int func(RecAnyFunc&) { return x; } 193 | }; 194 | 195 | TEST_CASE("Any can be used for recursive CRTP", "[raspberry]") { 196 | RecAnyFunc rat = RecAnyTester{7}; 197 | REQUIRE(rat.func(rat) == 7); 198 | 199 | rat = RecAnyTester{42}; 200 | REQUIRE(rat.func(rat) == 42); 201 | 202 | RecAnyFunc rat2 = std::move(rat); 203 | rat = RecAnyTester{13}; 204 | REQUIRE(rat.func(rat) == 13); 205 | REQUIRE(rat2.func(rat2) == 42); 206 | }; 207 | 208 | struct RecAnyFuncValue final : raspberry::Any< 209 | FuncConcept 210 | > { using Any::Any; }; 211 | 212 | struct RecAnyValueTester { 213 | int x; 214 | int func(RecAnyFuncValue) { return x; } 215 | }; 216 | 217 | TEST_CASE("Recursive Any concepts can accept Any value types", "[raspberry]") { 218 | RecAnyFuncValue rat1 = RecAnyValueTester{7}; 219 | RecAnyFuncValue rat2 = RecAnyValueTester{42}; 220 | REQUIRE(rat1.func(std::move(rat2)) == 7); 221 | }; 222 | 223 | using AnyFuncBase = raspberry::Any>; 224 | 225 | using AnySquareBase = raspberry::Any>; 226 | 227 | using AnyFuncSquare = raspberry::Any; 228 | 229 | TEST_CASE("Anys can be used as a base concepts", "[raspberry]") { 230 | AnyFuncSquare f = SomeFunc{}; 231 | 232 | REQUIRE(f.func() == 42); 233 | REQUIRE(f.square(12) == 144); 234 | } 235 | 236 | TEST_CASE("Derived Anys can be upcast to base Anys", "[raspberry]") { 237 | AnyFuncSquare f = SomeFunc{}; 238 | AnyFuncBase f2 = std::move(f); 239 | 240 | REQUIRE(f2.func() == 42); 241 | } 242 | 243 | using AnyFunc1 = raspberry::Any>; 244 | using AnyFunc2 = raspberry::Any, SquareConcept>; 245 | 246 | TEST_CASE("Conversion between unrelated Anys is possible", "[raspberry]") { 247 | AnyFunc2 f1 = SomeFunc{}; 248 | AnyFunc1 f2 = std::move(f1); 249 | 250 | REQUIRE(f2.func() == 42); 251 | } 252 | 253 | using AnyFuncAllOverloads = raspberry::Any< 254 | FuncConcept, 255 | FuncConcept 256 | >; 257 | 258 | using AnyFuncAllRefOverloads = raspberry::Any< 259 | FuncConcept, 260 | FuncConcept, 261 | FuncConcept, 262 | FuncConcept 263 | >; 264 | 265 | struct FuncAllOverloadsTest { 266 | int func() { return 1; } 267 | int func() const { return 2; } 268 | }; 269 | 270 | struct FuncAllRefOverloadsTest { 271 | int func() & { return 3; } 272 | int func() const & { return 4; } 273 | int func() && { return 5; } 274 | int func() const && { return 6; } 275 | }; 276 | 277 | TEST_CASE("Concepts support all forms of overloading", "[raspberry]") { 278 | AnyFuncAllOverloads afao = FuncAllOverloadsTest{}; 279 | AnyFuncAllRefOverloads afaro = FuncAllRefOverloadsTest{}; 280 | 281 | REQUIRE(static_cast(afao).func() == 1); 282 | REQUIRE(static_cast(afao).func() == 2); 283 | REQUIRE(static_cast(afaro).func() == 3); 284 | REQUIRE(static_cast(afaro).func() == 4); 285 | REQUIRE(static_cast(afaro).func() == 5); 286 | REQUIRE(static_cast(afaro).func() == 6); 287 | }; 288 | 289 | TEST_CASE("Pointers are captured by value and dereferenced", "[raspberry]") { 290 | RefDetector rd; 291 | REQUIRE(rd.value == 0); 292 | 293 | AnyRefDetector ard = &rd; 294 | REQUIRE(rd.value == 0); 295 | 296 | ard.ref_detect(42); 297 | REQUIRE(rd.value == 42); 298 | } 299 | 300 | TEST_CASE("std::unique_ptr is captured by value and dereferenced", "[raspberry]") { 301 | auto rdp = std::make_unique(); 302 | auto* rd = rdp.get(); 303 | REQUIRE(rd->value == 0); 304 | 305 | AnyRefDetector ard = std::move(rdp); 306 | REQUIRE(rd->value == 0); 307 | 308 | ard.ref_detect(42); 309 | REQUIRE(rd->value == 42); 310 | } 311 | 312 | TEST_CASE("std::shared_ptr is captured by value and dereferenced", "[raspberry]") { 313 | auto rd = std::make_shared(); 314 | REQUIRE(rd->value == 0); 315 | 316 | AnyRefDetector ard = rd; 317 | REQUIRE(rd->value == 0); 318 | 319 | ard.ref_detect(42); 320 | REQUIRE(rd->value == 42); 321 | } 322 | -------------------------------------------------------------------------------- /include/raspberry/raspberry.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RASPBERRY_HPP 2 | #define RASPBERRY_HPP 3 | 4 | #include 5 | #include 6 | 7 | /// Implementation detail for RASPBERRY_DECL_METHOD. Unstable. 8 | #define RASPBERRY_DETAIL_QUALIFIED_METHOD(ConceptName, FuncName, CVQualifier, RefQualifier) \ 9 | template \ 10 | struct ConceptName { \ 11 | private: \ 12 | template \ 13 | friend class raspberry::_detail::BaseAny; \ 14 | template \ 15 | friend struct raspberry::_detail::Any_BeamConf; \ 16 | template \ 17 | friend struct raspberry::_detail::anyimpl::AnyImpl_BeamConf; \ 18 | template \ 19 | friend struct raspberry::_detail::anyimplbase::AnyImplBase_BeamConf; \ 20 | template \ 21 | struct Virtual : Next { \ 22 | using Next::FuncName; \ 23 | virtual R FuncName(Args...) CVQualifier RefQualifier = 0; \ 24 | }; \ 25 | template \ 26 | struct Virtual : Next { \ 27 | virtual R FuncName(Args...) CVQualifier RefQualifier = 0; \ 28 | }; \ 29 | template \ 30 | struct VirtualImpl : Base { \ 31 | virtual R FuncName(Args... args) CVQualifier RefQualifier override final { \ 32 | using Value = typename Impl::value_type; \ 33 | using QValue = raspberry::_detail::MakeRef_t; \ 34 | const auto& self = static_cast(*this); \ 35 | const auto& value = self.get_value(); \ 36 | return const_cast(value).FuncName(std::forward(args)...); \ 37 | } \ 38 | }; \ 39 | template \ 40 | struct NonVirtual : Next { \ 41 | using Next::FuncName; \ 42 | R FuncName(Args... args) CVQualifier RefQualifier { \ 43 | using Base = raspberry::_detail::AnyImplBase>; \ 44 | using QBase = raspberry::_detail::MakeRef_t; \ 45 | auto& self = static_cast(*this); \ 46 | auto& base = self._raspberry_get_impl(); \ 47 | return const_cast(base).FuncName(std::forward(args)...); \ 48 | } \ 49 | }; \ 50 | template \ 51 | struct NonVirtual : Next { \ 52 | R FuncName(Args... args) CVQualifier RefQualifier { \ 53 | using Base = raspberry::_detail::AnyImplBase>; \ 54 | using QBase = raspberry::_detail::MakeRef_t; \ 55 | const auto& self = static_cast(*this); \ 56 | const auto& base = self._raspberry_get_impl(); \ 57 | return const_cast(base).FuncName(std::forward(args)...); \ 58 | } \ 59 | }; \ 60 | } 61 | 62 | /// Declares a concept named ConceptName that implements the FuncName method. 63 | #define RASPBERRY_DECL_METHOD(ConceptName, FuncName) \ 64 | template \ 65 | struct ConceptName; \ 66 | RASPBERRY_DETAIL_QUALIFIED_METHOD(ConceptName, FuncName, , ); \ 67 | RASPBERRY_DETAIL_QUALIFIED_METHOD(ConceptName, FuncName, , &); \ 68 | RASPBERRY_DETAIL_QUALIFIED_METHOD(ConceptName, FuncName, , &&); \ 69 | RASPBERRY_DETAIL_QUALIFIED_METHOD(ConceptName, FuncName, const, ); \ 70 | RASPBERRY_DETAIL_QUALIFIED_METHOD(ConceptName, FuncName, const, &); \ 71 | RASPBERRY_DETAIL_QUALIFIED_METHOD(ConceptName, FuncName, const, &&) 72 | 73 | namespace raspberry { 74 | 75 | namespace _detail { 76 | 77 | namespace typelist { 78 | 79 | /// A simple list of types. 80 | template 81 | struct TypeList {}; 82 | 83 | template 84 | struct TypeListCat; 85 | 86 | /// Concatenates any number of TypeLists into a single TypeList. 87 | template 88 | using TypeListCat_t = typename TypeListCat::type; 89 | 90 | template 91 | struct TypeListCat, TypeList, Tail...> { 92 | using type = TypeListCat_t, Tail...>; 93 | }; 94 | 95 | template 96 | struct TypeListCat { 97 | using type = T; 98 | }; 99 | 100 | template <> 101 | struct TypeListCat<> { 102 | using type = TypeList<>; 103 | }; 104 | 105 | } // namespace typelist 106 | 107 | using typelist::TypeList; 108 | using typelist::TypeListCat_t; 109 | 110 | namespace makeref { 111 | 112 | template 113 | struct MakeRef { 114 | using type = T&; 115 | }; 116 | 117 | /// Given T with underlying type U, maps { U -> U&, U& -> U&, U&& -> U&& }. 118 | template 119 | using MakeRef_t = typename MakeRef::type; 120 | 121 | template 122 | struct MakeRef { 123 | using type = T&&; 124 | }; 125 | 126 | } // namespace makeref 127 | 128 | using makeref::MakeRef_t; 129 | 130 | // Forward declarations. 131 | template 132 | class BaseAny; 133 | template 134 | class Any; 135 | 136 | namespace inheritance { 137 | 138 | template 139 | struct InheritAll; 140 | 141 | /// Inherits from each `Config::Base` for each `T` in `Types`. 142 | template 143 | using InheritAll_t = typename InheritAll::type; 144 | 145 | template 146 | struct InheritAll> { 147 | struct type : Config::template Base... {}; 148 | }; 149 | 150 | template 151 | struct BeamInheritance; 152 | 153 | /// Converts multiple inheritance into a chain of single inheritance (to avoid arithmetic on `this` pointer). 154 | /// `Conf::Base` is the leaf base class. 155 | /// `Conf::Link` is invoked using mutual recursion. 156 | /// - `H` is the current element in `Types...` 157 | /// - `B` is the current base class that `Link` must inherit from (it will either be the next `Link` or `Base`) 158 | /// - `T...` is a list of the remaining elements of `Types...` 159 | template 160 | using BeamInheritance_t = typename BeamInheritance::type; 161 | 162 | template 163 | struct BeamInheritance, SuperConf> { 164 | using type = typename Conf::Base; 165 | }; 166 | 167 | template 168 | struct BeamInheritance, SuperConf> { 169 | using type = typename Conf::template Link>, TailConcepts...>; 170 | }; 171 | 172 | } // namespace inheritance 173 | 174 | using inheritance::InheritAll_t; 175 | using inheritance::BeamInheritance_t; 176 | 177 | namespace find_overload { 178 | 179 | template 180 | struct FindOverloadOrVoid; 181 | 182 | /// Given T = C, searches Us for C and returns it, else returns void. 183 | template 184 | using FindOverloadOrVoid_t = typename FindOverloadOrVoid::type; 185 | 186 | template 187 | struct FindOverloadOrVoid { 188 | using type = void; 189 | }; 190 | 191 | template 192 | struct FindOverloadOrVoid { 193 | using type = FindOverloadOrVoid_t; 194 | }; 195 | 196 | template