c++tuples

constexpr std::tuple-like utility so you can use it with non constexpr tuple members


It would be nice if there was something like tuple but that didn't actually construct the types, but just held them as template parameters, with the features of std::tuple, the indexing and such. Is there something like tuple that doesn't actually need to construct the objects? And you do something like get the type instead of the object with std::get<0>(tuple). Sometimes tuples need to be constexpr for constexpr and consteval evaluation and it won't work if any tuple members are not constexpr. For example if I add a constructor to one of my tuple members it doesn't compile anymore.

#include <tuple>
#include <cstdint>
#include <cstdio>
#include <array>
#include <tuple>
template <uint32_t N>
struct BitfieldBits
{
    constexpr static inline uint64_t num_bits = N;
};

struct DepthMode : BitfieldBits<2>
{
};
struct UseCulling : BitfieldBits<1>
{
};
struct VertexShaderID : BitfieldBits<8>
{
};

template <typename ... T>
struct MyBitfield
{
    uint64_t bitfield;

    /* HERE, IS THERE A WAY TO HOLD THE TYPES BUT WITHOUT THE ACTUAL OBJECTS */
    constexpr static inline std::tuple<T...> tuple{};

    constexpr static inline std::array<uint32_t, sizeof ... (T)> bit_shift_offsets = []() consteval
        {
            std::array<uint32_t, sizeof ... (T)> arr;

            auto lambda = [&] <int offset, int idx>(const auto& self) consteval
            {
                if constexpr (idx >= sizeof ... (T))
                    return;

                else
                {// SO I CAN ACCESS IT HERE THROUGH A 'TYPE' std::get<idx>(tuple)::num_bits
                    arr[idx] = offset;
                    self.template operator()<offset + std::get<idx>(tuple).num_bits, idx + 1> (self);
                }
            };

            lambda.template operator() <0, 0> (lambda);
            return arr;
        }();
};

int main(int argc, char* argv[])
{
    MyBitfield<DepthMode, UseCulling, VertexShaderID> my_bitfield;
    constexpr auto offset = my_bitfield.bit_shift_offsets[2];
}

Also, I'm aware that passing variadic arguments to template parameters (as a parameter pack) is kind of like its own tuple, but it's limited, such as not being able to index into it.


Solution

  • And you do something like get the type instead of the object with std::get<0>(tuple)

    Yes, you can use std::tuple_element_t<0, std::tuple<T...>> for that purpose.

    Replace the member variable

    constexpr static inline std::tuple<T...> tuple{};
    

    with

    template<size_t I>
    using element_t = std::tuple_element_t<I, std::tuple<T...>>;
    

    and then you can replace

    std::get<idx>(tuple).num_bits
    

    with

    element_t<idx>::num_bits