/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * 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. */ #pragma once #include #include #include #include #include #include #include namespace folly { #if defined(__cpp_lib_type_identity) && __cpp_lib_type_identity >= 201806L using std::type_identity; using std::type_identity_t; #else /// type_identity_t /// type_identity /// /// mimic: std::type_identity_t, std::type_identity, c++20 template struct type_identity { using type = T; }; template using type_identity_t = typename type_identity::type; #endif /// tag_t /// tag /// /// A generic type-list value type and value. /// /// A type-list is a class template parameterized by a pack of types. template struct tag_t {}; template inline constexpr tag_t tag{}; /// vtag_t /// vtag /// /// A generic value-list value type and value. /// /// A value-list is a class template parameterized by a pack of values. template struct vtag_t {}; template inline constexpr vtag_t vtag{}; template using index_constant = std::integral_constant; /// always_false /// /// A variable template that is always false but requires template arguments to /// be provided (which are then ignored). This is useful in very specific cases /// where we want type-dependent expressions to defer static_assert's. /// /// A common use-case is for exhaustive constexpr if branches: /// /// template /// void foo(T value) { /// if constexpr (std::is_integral_v) foo_integral(value); /// else if constexpr (std::is_same_v) foo_string(value); /// else static_assert(always_false, "Unsupported type"); /// } /// /// If we had used static_assert(false), then this would always fail to compile, /// even if foo is never instantiated! /// /// Another use case is if a template that is expected to always be specialized /// is erroneously instantiated with the base template. /// /// template /// struct Foo { /// static_assert(always_false, "Unsupported type"); /// }; /// template <> /// struct Foo {}; /// /// Foo a; // fine /// Foo b; // fails! And you get a nice (custom) error message /// /// This is similar to leaving the base template undefined but we get a nicer /// compiler error message with static_assert. template inline constexpr bool always_false = false; namespace detail { template struct require_sizeof_ { static_assert(always_false, "application of sizeof fails substitution"); }; template struct require_sizeof_ { template using apply_t = V; static constexpr std::size_t size = sizeof(T); }; } // namespace detail /// require_sizeof /// /// Equivalent to sizeof, but with a static_assert enforcing that application of /// sizeof would not fail substitution. template constexpr std::size_t require_sizeof = detail::require_sizeof_::size; /// is_complete /// is_complete_v /// /// It is tempting to define is_complete and is_complete_v, but ultimately these /// would be a bad idea. These traits are defined here to witness that these are /// intentionally excluded and not merely a missing feature. template struct is_complete { static_assert(always_false, "is_complete would break ODR"); }; template constexpr auto is_complete_v = is_complete::value; /// is_unbounded_array_v /// is_unbounded_array /// /// A trait variable and type to check if a given type is an unbounded array. /// /// mimic: std::is_unbounded_array_d, std::is_unbounded_array (C++20) template inline constexpr bool is_unbounded_array_v = false; template inline constexpr bool is_unbounded_array_v = true; template struct is_unbounded_array : std::bool_constant> {}; /// is_bounded_array_v /// is_bounded_array /// /// A trait variable and type to check if a given type is a bounded array. /// /// mimic: std::is_bounded_array_d, std::is_bounded_array (C++20) template inline constexpr bool is_bounded_array_v = false; template inline constexpr bool is_bounded_array_v = true; template struct is_bounded_array : std::bool_constant> {}; /// is_instantiation_of_v /// is_instantiation_of /// instantiated_from /// uncvref_instantiated_from /// /// A trait variable and type to check if a given type is an instantiation of a /// class template. And corresponding concepts. /// /// Note that this only works with type template parameters. It does not work /// with non-type template parameters, template template parameters, or alias /// templates. template