C++11 constexpr 构造函数如何从指针完全初始化 C 样式数组?
How a C++11 constexpr constructor fully initialize a C-style array from a pointer?
在 c++11 中,我想要一个如下所示的结构:
template<unsigned n> struct bytes_block {
char data[n];
constexpr bytes_block(char const *s):data(....) {}
};
可以安全地假设构造函数参数 's' 指向一个内存区域,在该区域中至少可以从 's' 开始复制 n 个连续字符,而无需在构造函数中调用任何 UB .
但是我不知道如何填写上面的...
是否可以为 bytes_block 构造函数创建符合 C++11 的 constexpr 实现?可以创建任意数量的附加 constexpr 函数用作助手,当然只要它们只包含一个 return 语句。
您可以通过使用 std::make_index_sequence<n>
中的参数包进行索引来完成此操作。当然,这在C++11中是不存在的,但是很容易实现:
#include <cstddef>
#include <utility>
// Use `std::index_sequence` if available, otherwise implement it.
namespace detail {
#if __cplusplus < 201300L
template<class T, T... Ints>
struct integer_sequence {};
template<std::size_t... Ints>
using index_sequence = integer_sequence<std::size_t, Ints...>;
template<typename Firsts, typename Last>
struct index_sequence_eights_append;
template<std::size_t... N, std::size_t... M>
struct index_sequence_eights_append<index_sequence<N...>, index_sequence<M...>> {
using type = index_sequence<
N..., (sizeof...(N) + N)..., (2u * sizeof...(N) + N)..., (3u * sizeof...(N) + N)...,
(4u * sizeof...(N) + N)..., (5u * sizeof...(N) + N)..., (6u * sizeof...(N) + N)...,
(7u * sizeof...(N) + M)...
>;
};
template<std::size_t N>
struct make_index_sequence_helper {
using type = typename index_sequence_eights_append<typename make_index_sequence_helper<N / 8u>::type, typename make_index_sequence_helper<N - 7u * (N / 8u)>::type>::type;
};
template<> struct make_index_sequence_helper<0> { using type = index_sequence<>; };
template<> struct make_index_sequence_helper<1> { using type = index_sequence<0>; };
template<> struct make_index_sequence_helper<2> { using type = index_sequence<0, 1>; };
template<> struct make_index_sequence_helper<3> { using type = index_sequence<0, 1, 2>; };
template<> struct make_index_sequence_helper<4> { using type = index_sequence<0, 1, 2, 3>; };
template<> struct make_index_sequence_helper<5> { using type = index_sequence<0, 1, 2, 3, 4>; };
template<> struct make_index_sequence_helper<6> { using type = index_sequence<0, 1, 2, 3, 4, 5>; };
template<> struct make_index_sequence_helper<7> { using type = index_sequence<0, 1, 2, 3, 4, 5, 6>; };
// Has a template instantiation depth of `4 + (log_2(N) / 3)`
template<std::size_t N>
using make_index_sequence = typename make_index_sequence_helper<N>::type;
#else
using std::index_sequence;
using std::make_index_sequence;
#endif
}
然后构造函数变得非常简单,只需委托获取包并使用它进行索引即可:
template<unsigned n> struct bytes_block {
char data[n];
constexpr bytes_block(char const *s) : bytes_block(detail::make_index_sequence<n>{}, s) {}
private:
template<std::size_t... I>
constexpr bytes_block(detail::index_sequence<I...>, char const *s) : data{ s[I]... } {}
};
在 c++11 中,我想要一个如下所示的结构:
template<unsigned n> struct bytes_block {
char data[n];
constexpr bytes_block(char const *s):data(....) {}
};
可以安全地假设构造函数参数 's' 指向一个内存区域,在该区域中至少可以从 's' 开始复制 n 个连续字符,而无需在构造函数中调用任何 UB .
但是我不知道如何填写上面的...
是否可以为 bytes_block 构造函数创建符合 C++11 的 constexpr 实现?可以创建任意数量的附加 constexpr 函数用作助手,当然只要它们只包含一个 return 语句。
您可以通过使用 std::make_index_sequence<n>
中的参数包进行索引来完成此操作。当然,这在C++11中是不存在的,但是很容易实现:
#include <cstddef>
#include <utility>
// Use `std::index_sequence` if available, otherwise implement it.
namespace detail {
#if __cplusplus < 201300L
template<class T, T... Ints>
struct integer_sequence {};
template<std::size_t... Ints>
using index_sequence = integer_sequence<std::size_t, Ints...>;
template<typename Firsts, typename Last>
struct index_sequence_eights_append;
template<std::size_t... N, std::size_t... M>
struct index_sequence_eights_append<index_sequence<N...>, index_sequence<M...>> {
using type = index_sequence<
N..., (sizeof...(N) + N)..., (2u * sizeof...(N) + N)..., (3u * sizeof...(N) + N)...,
(4u * sizeof...(N) + N)..., (5u * sizeof...(N) + N)..., (6u * sizeof...(N) + N)...,
(7u * sizeof...(N) + M)...
>;
};
template<std::size_t N>
struct make_index_sequence_helper {
using type = typename index_sequence_eights_append<typename make_index_sequence_helper<N / 8u>::type, typename make_index_sequence_helper<N - 7u * (N / 8u)>::type>::type;
};
template<> struct make_index_sequence_helper<0> { using type = index_sequence<>; };
template<> struct make_index_sequence_helper<1> { using type = index_sequence<0>; };
template<> struct make_index_sequence_helper<2> { using type = index_sequence<0, 1>; };
template<> struct make_index_sequence_helper<3> { using type = index_sequence<0, 1, 2>; };
template<> struct make_index_sequence_helper<4> { using type = index_sequence<0, 1, 2, 3>; };
template<> struct make_index_sequence_helper<5> { using type = index_sequence<0, 1, 2, 3, 4>; };
template<> struct make_index_sequence_helper<6> { using type = index_sequence<0, 1, 2, 3, 4, 5>; };
template<> struct make_index_sequence_helper<7> { using type = index_sequence<0, 1, 2, 3, 4, 5, 6>; };
// Has a template instantiation depth of `4 + (log_2(N) / 3)`
template<std::size_t N>
using make_index_sequence = typename make_index_sequence_helper<N>::type;
#else
using std::index_sequence;
using std::make_index_sequence;
#endif
}
然后构造函数变得非常简单,只需委托获取包并使用它进行索引即可:
template<unsigned n> struct bytes_block {
char data[n];
constexpr bytes_block(char const *s) : bytes_block(detail::make_index_sequence<n>{}, s) {}
private:
template<std::size_t... I>
constexpr bytes_block(detail::index_sequence<I...>, char const *s) : data{ s[I]... } {}
};