如何在编译时将同质元组转换为数组?
How to convert a homogenous tuple to an array at compile time?
我想先说明一下,当我说同质元组时,我的意思是每个元素的类型都相同,或者每个元素都有一个 public 成员,它在所有元素中都是相同的类型元素。在这种情况下,public 成员也需要是 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...};
};
我相当确定它是正确的,唯一的问题是最后一行,但希望你能理解要点。
现在,数组是使用 Ns...
构建的。我希望能够从 type
构建数组(原因是 type
已经从元组中删除了重复类型(基于 .value
)并且也有在此代码的实际版本中排序的类型(基于 .value
)。相反,如果在编译时从数组中排序和删除重复值更容易,那么这也将被接受为答案。
所以理想情况下,我会编写某种模板化结构来创建数组(因为在结构中会有一个 static constexpr arr_type value =
成员),而在 Stuff
结构中,我会初始化 arr
像这样的成员:
static constexpr arr_type arr = detail::make_array_v<type>;
如果绝对必要,我愿意取消对 Int
结构的复制 construction/assignment 的限制。我不确定如何为此编写帮助程序 function/struct,感谢任何帮助。答案可以使用任何版本的 c++,包括 c++20。
我认为这以某种通用的方式解决了您的问题:
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;
}
它基本上是一个模板,具有 std::tuple
专门化 std::tuple
具有值列表的给定模板参数。
以下是可能的用法(假设 Char
与 char
的 Int
bur 相似):
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'});
该实现对 C++17 有效,我认为转换为 C++14 非常容易(您只需为 value
指定模板参数)。上面的测试需要 C++20 用于 std::array
.
的 constexpr
比较运算符
完整 godbolt.org 示例代码:https://godbolt.org/z/jkiA9R
我想先说明一下,当我说同质元组时,我的意思是每个元素的类型都相同,或者每个元素都有一个 public 成员,它在所有元素中都是相同的类型元素。在这种情况下,public 成员也需要是 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...};
};
我相当确定它是正确的,唯一的问题是最后一行,但希望你能理解要点。
现在,数组是使用 Ns...
构建的。我希望能够从 type
构建数组(原因是 type
已经从元组中删除了重复类型(基于 .value
)并且也有在此代码的实际版本中排序的类型(基于 .value
)。相反,如果在编译时从数组中排序和删除重复值更容易,那么这也将被接受为答案。
所以理想情况下,我会编写某种模板化结构来创建数组(因为在结构中会有一个 static constexpr arr_type value =
成员),而在 Stuff
结构中,我会初始化 arr
像这样的成员:
static constexpr arr_type arr = detail::make_array_v<type>;
如果绝对必要,我愿意取消对 Int
结构的复制 construction/assignment 的限制。我不确定如何为此编写帮助程序 function/struct,感谢任何帮助。答案可以使用任何版本的 c++,包括 c++20。
我认为这以某种通用的方式解决了您的问题:
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;
}
它基本上是一个模板,具有 std::tuple
专门化 std::tuple
具有值列表的给定模板参数。
以下是可能的用法(假设 Char
与 char
的 Int
bur 相似):
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'});
该实现对 C++17 有效,我认为转换为 C++14 非常容易(您只需为 value
指定模板参数)。上面的测试需要 C++20 用于 std::array
.
constexpr
比较运算符
完整 godbolt.org 示例代码:https://godbolt.org/z/jkiA9R