如何在编译时将同构元组转换为数组?

doo*_*pav 0 c++ compile-time variadic-templates stdtuple c++17

我想首先说明,当我说同构元组时,我的意思是每个元素的类型都是相同的,或者每个元素都有一个公共成员,该成员在所有元素中都是相同的类型。在这种情况下,公共成员也必须是static constexpr

这是描述我的问题的一段简化代码:

#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...};
};
Run Code Online (Sandbox Code Playgroud)

我相当确定它是正确的,唯一的问题是最后一行,但希望你明白要点。

现在,数组是使用Ns.... 我希望能够从而type不是构造数组(原因是type已经从元组中删除了重复类型(基于.value),并且还在.value此代码的实际版本中对类型进行了排序(基于))。如果相反,在编译时从数组中排序和删除重复值更容易,那么这也将被接受作为答案。

所以理想情况下,我会编写某种模板化结构来创建数组(因为在结构中会有一个static constexpr arr_type value =成员),并且在Stuff结构中,我会arr像这样初始化成员:

static constexpr arr_type arr = detail::make_array_v<type>;
Run Code Online (Sandbox Code Playgroud)

Int如果绝对必要,我愿意取消对结构的复制构造/分配的限制。我不知道如何为此编写一个辅助函数/结构,任何帮助表示赞赏。答案可以使用任何版本的 c++,直到并包括 c++20。

Hol*_*olt 5

我认为这以某种通用的方式解决了您的问题:

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;

}
Run Code Online (Sandbox Code Playgroud)

它基本上是一个模板std::tuple专业化std::tuple与值列表的模板参数的。

以下是可能的用法(假设Char类似于您的Intbur 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'});
Run Code Online (Sandbox Code Playgroud)

该实现对 C++17 有效,我认为转换为 C++14 很容易(你只需要为 指定模板参数value)。上面的测试需要 C++20constexpr作为std::array.


完整的 Godbolt.org 代码与您的示例:https ://godbolt.org/z/jkiA9R