1 /* 2 * Copyright 2014 Google Inc. All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef FRUIT_INJECTION_ERRORS_H 18 #define FRUIT_INJECTION_ERRORS_H 19 20 #include <fruit/impl/fruit_assert.h> 21 #include <fruit/impl/meta/set.h> 22 23 namespace fruit { 24 namespace impl { 25 26 template <typename... Ts> 27 struct AlwaysFalse { 28 static constexpr bool value = false; 29 }; 30 31 template <typename T> 32 struct NoBindingFoundError { 33 static_assert(AlwaysFalse<T>::value, "No explicit binding nor C::Inject definition was found for T."); 34 }; 35 36 template <typename T, typename C> 37 struct NoBindingFoundForAbstractClassError { 38 static_assert(AlwaysFalse<T>::value, 39 "No explicit binding was found for T, and note that C is an abstract class (so Fruit can't auto-inject " 40 "this type, " 41 "even if it has an Inject typedef or an INJECT annotation that will be ignored)."); 42 }; 43 44 template <typename... Ts> 45 struct RepeatedTypesError { 46 static_assert(AlwaysFalse<Ts...>::value, 47 "A type was specified more than once. Requirements and provided types should be unique."); 48 }; 49 50 template <typename... TypesInLoop> 51 struct SelfLoopError { 52 static_assert(AlwaysFalse<TypesInLoop...>::value, 53 "Found a loop in the dependencies! The types in TypesInLoop all depend on the next, and the " 54 "last one depends on the first."); 55 }; 56 57 template <typename T, typename C> 58 struct NonClassTypeError { 59 static_assert(AlwaysFalse<T>::value, "A non-class type T was specified. Use C instead."); 60 }; 61 62 template <typename AnnotatedT, typename T> 63 struct AnnotatedTypeError { 64 static_assert(AlwaysFalse<T>::value, "An annotated type was specified where a non-annotated type was expected."); 65 }; 66 67 template <typename C> 68 struct TypeAlreadyBoundError { 69 static_assert(AlwaysFalse<C>::value, "Trying to bind C but it is already bound."); 70 }; 71 72 template <typename RequiredSignature, typename SignatureInInjectTypedef> 73 struct RequiredFactoryWithDifferentSignatureError { 74 static_assert(AlwaysFalse<RequiredSignature>::value, 75 "The required C factory doesn't have the same signature as the Inject annotation in C."); 76 }; 77 78 template <typename Signature, typename SignatureInLambda> 79 struct AnnotatedSignatureDifferentFromLambdaSignatureError { 80 static_assert(AlwaysFalse<Signature>::value, 81 "The annotated signature specified is not the same as the lambda's signature (after removing " 82 "annotations)."); 83 }; 84 85 template <typename... DuplicatedTypes> 86 struct DuplicateTypesInComponentError { 87 static_assert(AlwaysFalse<DuplicatedTypes...>::value, 88 "The installed component provides some types that are already provided by the current " 89 "component."); 90 }; 91 92 template <typename... Requirements> 93 struct InjectorWithRequirementsError { 94 static_assert(AlwaysFalse<Requirements...>::value, 95 "Injectors can't have requirements. If you want Fruit to try auto-resolving the requirements " 96 "in the injector's scope, cast the component to a component with no requirements before " 97 "constructing the injector with it."); 98 }; 99 100 template <typename C, typename CandidateSignature> 101 struct InjectTypedefNotASignatureError { 102 static_assert(AlwaysFalse<C>::value, "C::Inject should be a typedef to a signature, e.g. C(int)"); 103 }; 104 105 template <typename C, typename SignatureReturnType> 106 struct InjectTypedefForWrongClassError { 107 static_assert(AlwaysFalse<C>::value, 108 "C::Inject is a signature, but does not return a C. Maybe the class C has no Inject typedef " 109 "and inherited the base class' one? If that's not the case, make sure it returns just C, not " 110 "C* or other types."); 111 }; 112 113 template <typename C> 114 struct InjectTypedefWithAnnotationError { 115 static_assert(AlwaysFalse<C>::value, 116 "C::Inject is a signature that returns an annotated type. The annotation must be removed, " 117 "Fruit will deduce the correct annotation based on how the required binding."); 118 }; 119 120 template <typename CandidateSignature> 121 struct NotASignatureError { 122 static_assert(AlwaysFalse<CandidateSignature>::value, 123 "CandidateSignature was specified as parameter, but it's not a signature. Signatures are of " 124 "the form MyClass(int, float)."); 125 }; 126 127 template <typename CandidateLambda> 128 struct NotALambdaError { 129 static_assert(AlwaysFalse<CandidateLambda>::value, 130 "CandidateLambda was specified as parameter, but it's not a lambda."); 131 }; 132 133 template <typename Signature> 134 struct ConstructorDoesNotExistError { 135 static_assert(AlwaysFalse<Signature>::value, "The specified constructor does not exist."); 136 }; 137 138 template <typename I, typename C> 139 struct NotABaseClassOfError { 140 static_assert(AlwaysFalse<I>::value, "I is not a base class of C."); 141 }; 142 143 template <typename ProviderType> 144 struct FunctorUsedAsProviderError { 145 static_assert(AlwaysFalse<ProviderType>::value, 146 "A stateful lambda or a non-lambda functor was used as provider. Only functions and stateless " 147 "lambdas can be used as providers."); 148 }; 149 150 template <typename... ComponentRequirements> 151 struct ComponentWithRequirementsInInjectorError { 152 static_assert(AlwaysFalse<ComponentRequirements...>::value, 153 "When using the two-argument constructor of Injector, the component used as second parameter " 154 "must not have requirements (while the normalized component can), but the specified component " 155 "requires ComponentRequirements."); 156 }; 157 158 template <typename... UnsatisfiedRequirements> 159 struct UnsatisfiedRequirementsInNormalizedComponentError { 160 static_assert(AlwaysFalse<UnsatisfiedRequirements...>::value, 161 "The requirements in UnsatisfiedRequirements are required by the NormalizedComponent but are " 162 "not provided by the Component (second parameter of the Injector constructor)."); 163 }; 164 165 template <typename... TypesNotProvided> 166 struct TypesInInjectorNotProvidedError { 167 static_assert(AlwaysFalse<TypesNotProvided...>::value, 168 "The types in TypesNotProvided are declared as provided by the injector, but none of the two " 169 "components passed to the Injector constructor provides them."); 170 }; 171 172 template <typename... TypesProvidedAsConstOnly> 173 struct TypesInInjectorProvidedAsConstOnlyError { 174 static_assert( 175 AlwaysFalse<TypesProvidedAsConstOnly...>::value, 176 "The types in TypesProvidedAsConstOnly are declared as non-const provided types by the injector, but the " 177 "components passed to the Injector constructor provide them as const only. You should mark them as const in the " 178 "injector (e.g., switching from Injector<T> to Injector<const T>) or mark them as non-const in the " 179 "Component/NormalizedComponent (e.g. switching from [Normalized]Component<const T> to " 180 "[Normalized]Component<T>)."); 181 }; 182 183 template <typename T> 184 struct TypeNotProvidedError { 185 static_assert(AlwaysFalse<T>::value, 186 "Trying to get an instance of T, but it is not provided by this Provider/Injector."); 187 }; 188 189 template <typename T> 190 struct TypeProvidedAsConstOnlyError { 191 static_assert( 192 AlwaysFalse<T>::value, 193 "Trying to get an instance of T, but it is only provided as a constant by this Provider/Injector and a non-const " 194 "pointer/reference/Provider was requested. You should either switch to injecting a const value (e.g. switching " 195 "from" 196 " injecting T*, T&, std::unique_ptr<T> or Provider<T> to injecting a T, const T*, const T& or Provider<const T>) " 197 "or get the value from an Injector/Provider that provides it as a non-const type (e.g. switching from calling " 198 "get " 199 "on an Injector<const T> or on a Provider<const T> to calling get on an Injector<T> or a Provider<T>)."); 200 }; 201 202 template <typename T> 203 struct NonConstBindingRequiredButConstBindingProvidedError { 204 static_assert( 205 AlwaysFalse<T>::value, 206 "The type T was provided as constant, however one of the constructors/providers/factories in this component " 207 "requires it as a non-constant (or this Component declares it as a non-const provided/required type). " 208 "If you want to only have a const binding for this type, you should change the places that use the type to " 209 "inject " 210 "a constant value (e.g. T, const T*, const T& and Provider<const T> are ok while you should avoid injecting T*, " 211 "T&," 212 " std::unique_ptr<T> and Provider<T>) and if the type is in Component<...> make sure that it's marked as const " 213 "there" 214 " (e.g. Component<const T> and Component<Required<const T>> are ok while Component<T> and Component<Required<T>> " 215 "are " 216 "not. " 217 "On the other hand, if you want to have a non-const binding for this type, you should switch to a non-const " 218 "bindInstance (if you're binding an instance) or changing any installed component functions to declare the type " 219 "as " 220 "non-const, e.g. Component<T> or Component<Required<T>> instead of Component<const T> and " 221 "Component<Required<const T>>."); 222 }; 223 224 template <typename C, typename InjectSignature> 225 struct NoConstructorMatchingInjectSignatureError { 226 static_assert(AlwaysFalse<C>::value, 227 "C contains an Inject typedef but it's not constructible with the specified types"); 228 }; 229 230 template <typename ExpectedSignature, typename FunctorSignature> 231 struct FunctorSignatureDoesNotMatchError { 232 static_assert(AlwaysFalse<ExpectedSignature>::value, 233 "Unexpected functor signature (it should be the same as ExpectedSignature minus any Assisted " 234 "types)."); 235 }; 236 237 template <typename Signature> 238 struct FactoryReturningPointerError { 239 static_assert(AlwaysFalse<Signature>::value, 240 "The specified factory returns a pointer. This is not supported; return a value or an " 241 "std::unique_ptr instead."); 242 }; 243 244 template <typename Lambda> 245 struct LambdaWithCapturesError { 246 // It's not guaranteed by the standard, but it's reasonable to expect lambdas with no captures 247 // to be empty. This is always the case in GCC and Clang, but is not guaranteed to work in all 248 // conforming C++ compilers. If this error happens for a lambda with no captures, please file a 249 // bug at https://github.com/google/fruit/issues and indicate the compiler (with version) that 250 // you're using. 251 static_assert(AlwaysFalse<Lambda>::value, "Only lambdas with no captures are supported."); 252 }; 253 254 template <typename Lambda> 255 struct NonTriviallyCopyableLambdaError { 256 // It's not guaranteed by the standard, but it's reasonable to expect lambdas with no captures 257 // to be trivially copyable. This is always the case in GCC and Clang, but is not guaranteed to 258 // work in all conforming C++ compilers. If this error happens for a lambda with no captures, 259 // please file a bug at https://github.com/google/fruit/issues and indicate the compiler (with 260 // version) that you're using. 261 static_assert(AlwaysFalse<Lambda>::value, 262 "Only trivially copyable lambdas are supported. Make sure that your lambda has no captures."); 263 }; 264 265 template <typename C> 266 struct CannotConstructAbstractClassError { 267 static_assert(AlwaysFalse<C>::value, "The specified class can't be constructed because it's an abstract class."); 268 }; 269 270 template <typename C> 271 struct InterfaceBindingToSelfError { 272 static_assert(AlwaysFalse<C>::value, 273 "The type C was bound to itself. If this was intentional, to \"tell Fruit to inject the type" 274 " C\", this binding is unnecessary, just remove it. bind<I,C>() is to tell Fruit about" 275 " base-derived class relationships."); 276 }; 277 278 template <typename TypeParameter, typename TypeOfValue> 279 struct TypeMismatchInBindInstanceError { 280 static_assert(AlwaysFalse<TypeParameter>::value, 281 "A type parameter was specified in bindInstance() but it doesn't match the value type" 282 " (even after removing the fruit::Annotation<>, if any). Please change the type parameter" 283 " to be the same as the type of the value (or a subclass)."); 284 }; 285 286 template <typename RequiredType> 287 struct RequiredTypesInComponentArgumentsError { 288 static_assert(AlwaysFalse<RequiredType>::value, 289 "A Required<...> type was passed as a non-first template parameter to fruit::Component or " 290 "fruit::NormalizedComponent. " 291 "All required types (if any) should be passed together as a single Required<> type passed as the first " 292 "type argument of fruit::Component (and fruit::NormalizedComponent). For example, write " 293 "fruit::Component<fruit::Required<Foo, Bar>, Baz> instead of " 294 "fruit::Component<fruit::Required<Foo>, fruit::Required<Bar>, Baz>."); 295 }; 296 297 template <typename T> 298 struct NonInjectableTypeError { 299 static_assert( 300 AlwaysFalse<T>::value, 301 "The type T is not injectable. Injectable types are of the form X, X*, X&, const X, const X*, const X&, " 302 "std::shared_ptr<X>, or Provider<X> where X is a fundamental type (excluding void), a class, a struct or " 303 "an enum."); 304 }; 305 306 template <typename T> 307 struct ConstBindingDeclaredAsRequiredButNonConstBindingRequiredError { 308 static_assert( 309 AlwaysFalse<T>::value, 310 "The type T was declared as a const Required type in the returned Component, however a non-const binding is " 311 "required. You should either change all the usages of this type so that they no longer require a non-const " 312 "binding " 313 "(i.e., you shouldn't inject T*, T& or std::shared_ptr<T>) or you should remove the 'const' in the type of the " 314 "returned Component, e.g. changing fruit::Component<fruit::Required<const T, ...>, ...> to " 315 "fruit::Component<fruit::Required<T, ...>, ...>."); 316 }; 317 318 template <typename T> 319 struct ProviderReturningPointerToAbstractClassWithNoVirtualDestructorError { 320 static_assert( 321 AlwaysFalse<T>::value, 322 "registerProvider() was called with a lambda that returns a pointer to T, but T is an abstract class with no " 323 "virtual destructor so when the injector is deleted Fruit will be unable to call the right destructor (the one " 324 "of " 325 "the concrete class that was then casted to T). You must either add a virtual destructor to T or change the " 326 "registerProvider() call to return a pointer to the concrete class (and then add a bind<T, TImpl>() so that T is " 327 "bound)."); 328 }; 329 330 template <typename T> 331 struct MultibindingProviderReturningPointerToAbstractClassWithNoVirtualDestructorError { 332 static_assert( 333 AlwaysFalse<T>::value, 334 "registerMultibindingProvider() was called with a lambda that returns a pointer to T, but T is an abstract class " 335 "with no virtual destructor so when the injector is deleted Fruit will be unable to call the right destructor " 336 "(the " 337 "one of the concrete class that was then casted to T). You must add a virtual destructor to T or replace the " 338 "registerMultibindingProvider() with a registerProvider() for the concrete class and an addMultibinding() for T. " 339 "Note that with the latter, if you end up with multiple addMultibinding() calls for the same concrete class, " 340 "there will be only one instance of the concrete class in the injector, not one per addMultibdinding() call; if " 341 "you want separate instances you might want to use annotated injection for the concrete class (so that there's " 342 "one " 343 "instance per annotation)."); 344 }; 345 346 template <typename T> 347 struct RegisterFactoryForUniquePtrOfAbstractClassWithNoVirtualDestructorError { 348 static_assert(AlwaysFalse<T>::value, 349 "registerFactory() was called with a lambda that returns a std::unique_ptr<T>, but T is an abstract " 350 "class with no " 351 "virtual destructor so when the returned std::unique_ptr<T> object is deleted the wrong destructor " 352 "will be called " 353 "(T's destructor instead of the one of the concrete class that was then casted to T). You must add a " 354 "virtual destructor to T."); 355 }; 356 357 template <typename BaseFactory, typename DerivedFactory> 358 struct FactoryBindingForUniquePtrOfClassWithNoVirtualDestructorError { 359 static_assert( 360 AlwaysFalse<BaseFactory>::value, 361 "Fruit was trying to bind BaseFactory to DerivedFactory but the return type of BaseFactory is a std::unique_ptr " 362 "of " 363 "a class with no virtual destructor, so when the std::unique_ptr object is destroyed the wrong destructor would " 364 "be " 365 "called (the one in the base class instead of the derived class). To avoid this, you must add a virtual " 366 "destructor to the base class."); 367 }; 368 369 template <typename Arg> 370 struct IncorrectArgTypePassedToInstallComponentFuntionsError { 371 static_assert( 372 AlwaysFalse<Arg>::value, 373 "All arguments passed to installComponentFunctions() must be fruit::ComponentFunction<...> objects but an " 374 "argument with type Arg was passed instead."); 375 }; 376 377 struct LambdaWithCapturesErrorTag { 378 template <typename Lambda> 379 using apply = LambdaWithCapturesError<Lambda>; 380 }; 381 382 struct NonTriviallyCopyableLambdaErrorTag { 383 template <typename Lambda> 384 using apply = NonTriviallyCopyableLambdaError<Lambda>; 385 }; 386 387 struct FactoryReturningPointerErrorTag { 388 template <typename Signature> 389 using apply = FactoryReturningPointerError<Signature>; 390 }; 391 392 struct NoBindingFoundErrorTag { 393 template <typename T> 394 using apply = NoBindingFoundError<T>; 395 }; 396 397 struct RepeatedTypesErrorTag { 398 template <typename... Ts> 399 using apply = RepeatedTypesError<Ts...>; 400 }; 401 402 struct SelfLoopErrorTag { 403 template <typename... TypesInLoop> 404 using apply = SelfLoopError<TypesInLoop...>; 405 }; 406 407 struct NonClassTypeErrorTag { 408 template <typename T, typename C> 409 using apply = NonClassTypeError<T, C>; 410 }; 411 412 struct AnnotatedTypeErrorTag { 413 template <typename T, typename C> 414 using apply = AnnotatedTypeError<T, C>; 415 }; 416 417 struct TypeAlreadyBoundErrorTag { 418 template <typename C> 419 using apply = TypeAlreadyBoundError<C>; 420 }; 421 422 struct RequiredFactoryWithDifferentSignatureErrorTag { 423 template <typename RequiredSignature, typename SignatureInInjectTypedef> 424 using apply = RequiredFactoryWithDifferentSignatureError<RequiredSignature, SignatureInInjectTypedef>; 425 }; 426 427 struct AnnotatedSignatureDifferentFromLambdaSignatureErrorTag { 428 template <typename Signature, typename SignatureInLambda> 429 using apply = AnnotatedSignatureDifferentFromLambdaSignatureError<Signature, SignatureInLambda>; 430 }; 431 432 struct DuplicateTypesInComponentErrorTag { 433 template <typename... DuplicatedTypes> 434 using apply = DuplicateTypesInComponentError<DuplicatedTypes...>; 435 }; 436 437 struct InjectorWithRequirementsErrorTag { 438 template <typename... Requirements> 439 using apply = InjectorWithRequirementsError<Requirements...>; 440 }; 441 442 struct ComponentWithRequirementsInInjectorErrorTag { 443 template <typename... ComponentRequirements> 444 using apply = ComponentWithRequirementsInInjectorError<ComponentRequirements...>; 445 }; 446 447 struct InjectTypedefNotASignatureErrorTag { 448 template <typename C, typename TypeInInjectTypedef> 449 using apply = InjectTypedefNotASignatureError<C, TypeInInjectTypedef>; 450 }; 451 452 struct InjectTypedefForWrongClassErrorTag { 453 template <typename C, typename ReturnTypeOfInjectTypedef> 454 using apply = InjectTypedefForWrongClassError<C, ReturnTypeOfInjectTypedef>; 455 }; 456 457 struct InjectTypedefWithAnnotationErrorTag { 458 template <typename C> 459 using apply = InjectTypedefWithAnnotationError<C>; 460 }; 461 462 struct UnsatisfiedRequirementsInNormalizedComponentErrorTag { 463 template <typename... UnsatisfiedRequirements> 464 using apply = UnsatisfiedRequirementsInNormalizedComponentError<UnsatisfiedRequirements...>; 465 }; 466 467 struct TypesInInjectorNotProvidedErrorTag { 468 template <typename... TypesNotProvided> 469 using apply = TypesInInjectorNotProvidedError<TypesNotProvided...>; 470 }; 471 472 struct TypesInInjectorProvidedAsConstOnlyErrorTag { 473 template <typename... TypesProvidedAsConstOnly> 474 using apply = TypesInInjectorProvidedAsConstOnlyError<TypesProvidedAsConstOnly...>; 475 }; 476 477 struct FunctorUsedAsProviderErrorTag { 478 template <typename ProviderType> 479 using apply = FunctorUsedAsProviderError<ProviderType>; 480 }; 481 482 struct ConstructorDoesNotExistErrorTag { 483 template <typename Signature> 484 using apply = ConstructorDoesNotExistError<Signature>; 485 }; 486 487 struct NotABaseClassOfErrorTag { 488 template <typename I, typename C> 489 using apply = NotABaseClassOfError<I, C>; 490 }; 491 492 struct NotASignatureErrorTag { 493 template <typename CandidateSignature> 494 using apply = NotASignatureError<CandidateSignature>; 495 }; 496 497 struct NotALambdaErrorTag { 498 template <typename CandidateLambda> 499 using apply = NotALambdaError<CandidateLambda>; 500 }; 501 502 struct TypeNotProvidedErrorTag { 503 template <typename T> 504 using apply = TypeNotProvidedError<T>; 505 }; 506 507 struct TypeProvidedAsConstOnlyErrorTag { 508 template <typename T> 509 using apply = TypeProvidedAsConstOnlyError<T>; 510 }; 511 512 struct NonConstBindingRequiredButConstBindingProvidedErrorTag { 513 template <typename T> 514 using apply = NonConstBindingRequiredButConstBindingProvidedError<T>; 515 }; 516 517 struct NoConstructorMatchingInjectSignatureErrorTag { 518 template <typename C, typename InjectSignature> 519 using apply = NoConstructorMatchingInjectSignatureError<C, InjectSignature>; 520 }; 521 522 struct FunctorSignatureDoesNotMatchErrorTag { 523 template <typename ExpectedSignature, typename FunctorSignature> 524 using apply = FunctorSignatureDoesNotMatchError<ExpectedSignature, FunctorSignature>; 525 }; 526 527 struct CannotConstructAbstractClassErrorTag { 528 template <typename C> 529 using apply = CannotConstructAbstractClassError<C>; 530 }; 531 532 struct NoBindingFoundForAbstractClassErrorTag { 533 template <typename T, typename C> 534 using apply = NoBindingFoundForAbstractClassError<T, C>; 535 }; 536 537 struct InterfaceBindingToSelfErrorTag { 538 template <typename C> 539 using apply = InterfaceBindingToSelfError<C>; 540 }; 541 542 struct TypeMismatchInBindInstanceErrorTag { 543 template <typename TypeParameter, typename TypeOfValue> 544 using apply = TypeMismatchInBindInstanceError<TypeParameter, TypeOfValue>; 545 }; 546 547 struct RequiredTypesInComponentArgumentsErrorTag { 548 template <typename RequiredType> 549 using apply = RequiredTypesInComponentArgumentsError<RequiredType>; 550 }; 551 552 struct NonInjectableTypeErrorTag { 553 template <typename T> 554 using apply = NonInjectableTypeError<T>; 555 }; 556 557 struct ConstBindingDeclaredAsRequiredButNonConstBindingRequiredErrorTag { 558 template <typename T> 559 using apply = ConstBindingDeclaredAsRequiredButNonConstBindingRequiredError<T>; 560 }; 561 562 struct ProviderReturningPointerToAbstractClassWithNoVirtualDestructorErrorTag { 563 template <typename T> 564 using apply = ProviderReturningPointerToAbstractClassWithNoVirtualDestructorError<T>; 565 }; 566 567 struct MultibindingProviderReturningPointerToAbstractClassWithNoVirtualDestructorErrorTag { 568 template <typename T> 569 using apply = MultibindingProviderReturningPointerToAbstractClassWithNoVirtualDestructorError<T>; 570 }; 571 572 struct RegisterFactoryForUniquePtrOfAbstractClassWithNoVirtualDestructorErrorTag { 573 template <typename T> 574 using apply = RegisterFactoryForUniquePtrOfAbstractClassWithNoVirtualDestructorError<T>; 575 }; 576 577 struct FactoryBindingForUniquePtrOfClassWithNoVirtualDestructorErrorTag { 578 template <typename BaseFactory, typename DerivedFactory> 579 using apply = FactoryBindingForUniquePtrOfClassWithNoVirtualDestructorError<BaseFactory, DerivedFactory>; 580 }; 581 582 struct IncorrectArgTypePassedToInstallComponentFuntionsErrorTag { 583 template <typename Arg> 584 using apply = IncorrectArgTypePassedToInstallComponentFuntionsError<Arg>; 585 }; 586 587 } // namespace impl 588 } // namespace fruit 589 590 #endif // FRUIT_INJECTION_ERRORS_H 591