| /* |
| * 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 <functional> |
| |
| namespace fruit { |
| namespace impl { |
| namespace meta { |
| |
| template <typename T> |
| struct Type { |
| using type = T; |
| }; |
| |
| template <bool b> |
| struct Bool { |
| static constexpr bool value = b; |
| }; |
| |
| template <int n> |
| 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 <typename N> |
| 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<ErrorArgs...> up the instantiation chain, but without instantiating it right |
| // away, to allow shorter error stacktraces. |
| // Instantiating ErrorTag::apply<ErrorArgs...> must result in a static_assert error. |
| template <typename ErrorTag, typename... ErrorArgs> |
| struct Error {}; |
| |
| // Use as Catch(ExpressionThatMightThrow, ErrorTag, Handler) |
| // Handler(Error<ErrorTag, ErrorArgs...>) is called if ExpressionThatMightThrow throws ErrorTag. |
| struct Catch {}; |
| |
| // Use as CatchAll(ExpressionThatMightThrow, Handler) |
| // Handler(Error<ErrorTag, ErrorArgs...>) 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 <typename F, typename... Args> |
| struct apply : public F::template apply<Args...> {}; |
| }; |
| |
| // UnwrapType<Type<T>> is T. |
| template <typename WrappedType> |
| 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<T>>::type is T. |
| template <typename WrappedType> |
| struct TypeUnwrapper { |
| using type = UnwrapType<WrappedType>; |
| }; |
| |
| // Logical And with short-circuit evaluation. |
| struct And { |
| template <typename... MetaExprs> |
| struct apply { |
| using type = Bool<true>; |
| }; |
| |
| template <typename MetaExpr> |
| struct apply<MetaExpr> { |
| using type = MetaExpr; |
| }; |
| |
| template <typename MetaExpr, typename MetaExpr2> |
| struct apply<MetaExpr, MetaExpr2> { |
| using type = If(MetaExpr, MetaExpr2, Bool<false>); |
| }; |
| |
| template <typename MetaExpr, typename MetaExpr2, typename... MetaExprs> |
| struct apply<MetaExpr, MetaExpr2, MetaExprs...> { |
| using type = If(MetaExpr, If(MetaExpr2, And(MetaExprs...), Bool<false>), Bool<false>); |
| }; |
| }; |
| |
| // Logical Or with short-circuit evaluation. |
| struct Or { |
| template <typename... MetaExprs> |
| struct apply { |
| using type = Bool<false>; |
| }; |
| |
| template <typename MetaExpr> |
| struct apply<MetaExpr> { |
| using type = MetaExpr; |
| }; |
| |
| template <typename MetaExpr, typename MetaExpr2> |
| struct apply<MetaExpr, MetaExpr2> { |
| using type = If(MetaExpr, Bool<true>, MetaExpr2); |
| }; |
| |
| template <typename MetaExpr, typename MetaExpr2, typename... MetaExprs> |
| struct apply<MetaExpr, MetaExpr2, MetaExprs...> { |
| using type = If(MetaExpr, Bool<true>, If(MetaExpr2, Bool<true>, 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 <typename F> |
| struct apply { |
| struct type { |
| template <typename... Args> |
| struct apply { |
| struct type { |
| template <typename... MoreArgs> |
| 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 <typename F, typename... Args> |
| struct apply { |
| struct type { |
| template <typename... MoreArgs> |
| struct apply { |
| using type = F(Args..., MoreArgs...); |
| }; |
| }; |
| }; |
| }; |
| |
| struct IsSame { |
| template <typename T, typename U> |
| struct apply { |
| using type = Bool<false>; |
| }; |
| |
| template <typename T> |
| struct apply<T, T> { |
| using type = Bool<true>; |
| }; |
| }; |
| |
| struct Not { |
| template <typename B> |
| struct apply { |
| using type = Bool<!B::value>; |
| }; |
| }; |
| |
| struct IsNone { |
| template <typename T> |
| struct apply { |
| using type = Bool<false>; |
| }; |
| }; |
| |
| template <> |
| struct IsNone::apply<None> { |
| using type = Bool<true>; |
| }; |
| |
| template <typename T> |
| using Id = T; |
| |
| struct Identity { |
| template <typename T> |
| struct apply { |
| using type = T; |
| }; |
| }; |
| |
| template <typename T> |
| struct DebugTypeHelper { |
| static_assert(sizeof(T*) * 0 != 0, ""); |
| using type = T; |
| }; |
| |
| template <typename T> |
| using DebugType = typename DebugTypeHelper<T>::type; |
| |
| } // namespace meta |
| } // namespace impl |
| } // namespace fruit |
| |
| #endif // FRUIT_META_BASICS_H |