Как конструктор constexpr в C ++ 11 полностью инициализирует массив C в стиле из указателя? - PullRequest
0 голосов
/ 26 апреля 2020

В c ++ 11 я хочу иметь структуру, подобную следующей:

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

Можно смело предположить, что параметр конструктора 's' указывает на область памяти, где по крайней мере n последовательные символы можно скопировать, начиная с 's', без вызова какого-либо UB в конструкторе.

Однако я не знаю, как заполнить ... выше.

Может ли Будет ли реализована реализация constexpr для конструктора bytes_block, который бы соответствовал требованиям C ++ 11? Может быть создано любое количество дополнительных функций constexpr для использования в качестве помощников, если, конечно, они состоят только из одного оператора return.

1 Ответ

1 голос
/ 26 апреля 2020

Вы можете сделать это sh, проиндексировав пакет параметров из 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]... } {}
};
...