0

I want to preface this by stating that when I say homogenous tuple, I mean that either the type of every element is the same, or every element has a public member which is the same type across all elements. In this case the public member is also required to be static constexpr.

This is a simplified piece of code describing my issue:

#include <cstddef>
#include <tuple>
#include <type_traits>
#include <utility>

template <std::size_t N>
struct Int : std::integral_constant<std::size_t, N>
{
    Int() = default;
    Int(const Int&) = delete;
    Int(Int&&) = delete;

    Int& operator=(const Int&) = delete;
    Int& operator=(Int&&) = delete;
};

template <std::size_t... Ns>
struct Stuff
{
    using type = std::tuple<Int<Ns>...>;
    using arr_type = std::array<std::size_t, std::tuple_size_v<type>>;
    static constexpr arr_type arr = {Ns...};
};

I'm fairly sure it's correct, with the only issue being the last line, but hopefully you get the gist.

Right now, the array is constructed using Ns.... I want to be able to construct the array from type instead (the reason for this is that type has had duplicate types removed from the tuple (based on .value) and has also had the types sorted (based on .value) in the actual version of this code). If instead it's easier to sort and remove duplicate values from the array at compile time, then that will also be accepted as an answer.

So ideally I would write some sort of templated struct to create the array (as in the struct would have a static constexpr arr_type value = member), and in the Stuff struct, I would initialize the arr member like this:

static constexpr arr_type arr = detail::make_array_v<type>;

I'm willing to lift the restrictions on copy construction/assignment for the Int struct if absolutely necessary. I'm not sure how to write a helper function/struct for this, and any help is appreciated. The answer can use any version of c++ up to and including c++20.

doodspav
  • 290
  • 3
  • 11
  • Does this answer your question? [Convert std::tuple to std::array C++11](https://stackoverflow.com/questions/10604794/convert-stdtuple-to-stdarray-c11) – Nikita Smirnov Jan 02 '20 at 10:20
  • I don't think so - at least I definitely went to that post before posting my own question, and I couldn't get their code to work at compile time for me (that may have been me being an idiot but I like to think it wasn't) - I think the issues were that my element types aren't moveable or copyable - either way, the answer below works very well :) – doodspav Jan 02 '20 at 10:38

1 Answers1

6

I think this solves your problem in a somehow generic way:

namespace detail {

    template <class Tuple>
    struct make_array;

    template <class V, template <V N> class C, V... Ns>
    struct make_array<std::tuple<C<Ns>... >> {
        static constexpr std::array value{Ns... };
    };

    template <class Tuple>
    constexpr auto make_array_v = make_array<Tuple>::value;

}

It is basically a template with a std::tuple specialization for std::tuple of a given template argument with a list of values.

Here are possible usages (assuming Char is similar to your Int bur for char):

constexpr auto arr1 = detail::make_array_v<std::tuple<Int<42>, Int<38>, Int<57>>>;
static_assert(arr1 == std::array<std::size_t, 3>{42, 38, 57});

constexpr auto arr2 = detail::make_array_v<std::tuple<Char<'A'>, Char<'Z'>,
                                                      Char<'w'>, Char<'U'>>>;
static_assert(arr2 == std::array{'A', 'Z', 'w', 'U'});

The implementation is valid for C++17, and I think quite easy to convert for C++14 (you just have to specify the template arguments for value). The tests above require C++20 for the constexpr comparison operator for std::array.


Full godbolt.org code with your example: https://godbolt.org/z/jkiA9R

Holt
  • 36,600
  • 7
  • 92
  • 139
  • This is perfect!! Thank you so much :) – doodspav Jan 02 '20 at 10:35
  • ``` template class C, T... BSs, U... Bs, V... EMATs> struct make_array... >> { using type = std::array; static constexpr type value{chunk_resource_options(BSs, Bs, EMATs)... }; }; ``` in case you want to see what your answer got butchered into (but it worked perfectly :) ) – doodspav Jan 02 '20 at 11:09