/* * Copyright 2014 Google Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef FRUIT_META_BASICS_H #define FRUIT_META_BASICS_H #include namespace fruit { namespace impl { namespace meta { template struct Type { using type = T; }; template struct Bool { static constexpr bool value = b; }; template struct Int { static constexpr int value = n; }; // This was added to workaround a bug in MSVC 2017 15.5, that crashes when expanding Indexes::value... in some cases // (where Indexes is a template parameter pack of Int<...> types). // TODO: Remove this once MSVC 2017 is fixed and the fix has been out for some time. template constexpr int getIntValue() { return N::value; } // None is used as "the nullptr of metaprogramming". E.g. when a function has no meaningful value to // return, it can return None instead. struct None {}; struct If {}; // PropagateError(E, X) evaluates E then X. The result is X's result, but if E returns an error, // that's the result instead. struct PropagateError {}; // Used to propagate an ErrorTag::apply up the instantiation chain, but without instantiating it right // away, to allow shorter error stacktraces. // Instantiating ErrorTag::apply must result in a static_assert error. template struct Error {}; // Use as Catch(ExpressionThatMightThrow, ErrorTag, Handler) // Handler(Error) is called if ExpressionThatMightThrow throws ErrorTag. struct Catch {}; // Use as CatchAll(ExpressionThatMightThrow, Handler) // Handler(Error) is called if ExpressionThatMightThrow throws any error. struct CatchAll {}; // Call(F, Args...) is equivalent to F(Args...) in a metaexpression, except that Call(F, Args...) // also works when F is a metaexpression. struct Call { template struct apply : public F::template apply {}; }; // UnwrapType> is T. template using UnwrapType = typename WrappedType::type; // MSVC 14 has trouble specializing alias templates using expanded pack elements. // This is a known issue: // https://stackoverflow.com/questions/43411542/metaprogramming-failed-to-specialize-alias-template // The workaround is just to use a struct directly. // typename TypeUnwrapper>::type is T. template struct TypeUnwrapper { using type = UnwrapType; }; // Logical And with short-circuit evaluation. struct And { template struct apply { using type = Bool; }; template struct apply { using type = MetaExpr; }; template struct apply { using type = If(MetaExpr, MetaExpr2, Bool); }; template struct apply { using type = If(MetaExpr, If(MetaExpr2, And(MetaExprs...), Bool), Bool); }; }; // Logical Or with short-circuit evaluation. struct Or { template struct apply { using type = Bool; }; template struct apply { using type = MetaExpr; }; template struct apply { using type = If(MetaExpr, Bool, MetaExpr2); }; template struct apply { using type = If(MetaExpr, Bool, If(MetaExpr2, Bool, Or(MetaExprs...))); }; }; // Call(Call(DeferArgs(F), Args...), MoreArgs...) // // is equivalent to: // Result = F(Args..., MoreArgs...) // // Note that you can't write: // DeferArgs(F)(Args...)(MoreArgs...) // // Because Call must be used to call metafunctions that are metaexpressions. struct DeferArgs { template struct apply { struct type { template struct apply { struct type { template struct apply { using type = F(Args..., MoreArgs...); }; }; }; }; }; }; // Call(PartialCall(F, Args...), MoreArgs...) // // is equivalent to: // Result = F(Args..., MoreArgs...) // // Note that you can't write: // PartialCall(F, Args...)(MoreArgs...) // // Because Call must be used to call metafunctions that are metaexpressions. struct PartialCall { template struct apply { struct type { template struct apply { using type = F(Args..., MoreArgs...); }; }; }; }; struct IsSame { template struct apply { using type = Bool; }; template struct apply { using type = Bool; }; }; struct Not { template struct apply { using type = Bool; }; }; struct IsNone { template struct apply { using type = Bool; }; }; template <> struct IsNone::apply { using type = Bool; }; template using Id = T; struct Identity { template struct apply { using type = T; }; }; template struct DebugTypeHelper { static_assert(sizeof(T*) * 0 != 0, ""); using type = T; }; template using DebugType = typename DebugTypeHelper::type; } // namespace meta } // namespace impl } // namespace fruit #endif // FRUIT_META_BASICS_H