简体   繁体   English

C++11 constexpr 构造函数如何从指针完全初始化 C 样式数组?

[英]How a C++11 constexpr constructor fully initialize a C-style array from a pointer?

In c++11, I want to have a struct like the following:在 c++11 中,我想要一个如下结构:

template<unsigned n> struct bytes_block {
    char data[n];
    constexpr bytes_block(char const *s):data(....) {}
};

It can be safely assumed that the constructor parameter 's' points to a region of memory where at least n consecutive characters can be copied from starting at 's' from without invoking any UB in the constructor.可以安全地假设构造函数参数 's' 指向 memory 的区域,其中至少 n 个连续字符可以从从 's' 开始复制,而无需在构造函数中调用任何 UB。

I do not know how to fill in the... above, however.但是,我不知道如何填写上面的...。

Can a constexpr implementation for the bytes_block constructor be made which would be C++11 compliant?可以为 bytes_block 构造函数创建一个符合 C++11 的 constexpr 实现吗? Any number of additional constexpr functions may be created to be used as helpers, as long as of course they consist of only a single return statement.可以创建任意数量的附加 constexpr 函数用作助手,当然只要它们只包含一个 return 语句。

You can accomplish this by indexing with a parameter pack from std::make_index_sequence<n> .您可以通过使用来自std::make_index_sequence<n>的参数包进行索引来完成此操作。 Of course, this doesn't exist in C++11, but it's easy enough to implement:当然,这在 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
}

And then the constructor becomes as simple as delegating to get the pack and indexing with it:然后构造函数变得像委托获取包并使用它索引一样简单:

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]... } {}
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM