/* SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once /** \file * \ingroup bli * * C++ has a feature called "parameter packs" which allow building variadic templates. * This file has some utilities to work with such parameter packs. */ #include #include #include "BLI_utildefines.h" namespace blender { /** * A type that encodes a specific value. */ template struct TypeForValue { static constexpr T value = Element; }; /** * A type that encodes a list of values of the same type. * This is similar to #std::integer_sequence, but a bit more general. It's main purpose it to also * support enums instead of just ints. */ template struct ValueSequence { /** * Get the number of elements in the sequence. */ static constexpr size_t size() noexcept { return sizeof...(Elements); } /** * Get the element at a specific index. */ template static constexpr T at_index() { static_assert(I < sizeof...(Elements)); return std::tuple_element_t...>>::value; } /** * Return true if the element is in the sequence. */ template static constexpr bool contains() { return ((Element == Elements) || ...); } }; /** * A type that encodes a list of types. * #std::tuple can also encode a list of types, but has a much more complex implementation. */ template struct TypeSequence { /** * Get the number of types in the sequence. */ static constexpr size_t size() noexcept { return sizeof...(T); } /** * Get the type at a specific index. */ template using at_index = std::tuple_element_t>; }; namespace detail { template inline ValueSequence make_value_sequence_impl( std::index_sequence /* indices */) { return {}; } template inline ValueSequence::template contains() ? Value1 : Value2)...> make_two_value_sequence_impl(ValueSequence /* value1_indices */, std::index_sequence /* indices */) { return {}; }; } // namespace detail /** * Utility to create a #ValueSequence that has the same value at every index. */ template using make_value_sequence = decltype(detail::make_value_sequence_impl( std::make_index_sequence())); /** * Utility to create a #ValueSequence that contains two different values. The indices of where the * first value should be used are passed in. */ template using make_two_value_sequence = decltype(detail::make_two_value_sequence_impl( ValueSequence(), std::make_index_sequence())); namespace parameter_pack_utils_static_tests { enum class MyEnum { A, B }; static_assert(std::is_same_v, ValueSequence>); static_assert( std::is_same_v, ValueSequence>); } // namespace parameter_pack_utils_static_tests } // namespace blender