C 14:如何使用variadic模板创建值1-100的数组



我希望获得一个值 int buf[]={1...100}的数组。我希望可以使用variadic模板在编译时构建此数组。这就像列表理解Python/Haskell等。

但是C 11/14模板可以做到吗?谢谢

C 14 允许在编译时循环。

constexpr auto make_upto_100() {
    std::array< int, 100 > ret = {};
    for ( int i = 0; i != 100; ++ i ) ret[i] = i + 1;
    return ret;
}

C 11 允许像make_index_sequence这样的实用程序,它可能更像您的想法。(C 14也有std::[make_]index_sequence。)

template< std::size_t ... i >
struct index_sequence
    { typedef index_sequence< i ..., sizeof ... (i) > next; };
template< std::size_t last >
struct index_seq_maker
    { typedef typename index_seq_maker< last - 1 >::type::next type; };
template<>
struct index_seq_maker< 0 >
    { typedef index_sequence<> type; };
template< std::size_t n >
using make_index_sequence = typename index_seq_maker< n >::type;
template< int ... i >
constexpr
std::array< int, 100 >
make_upto_100( index_sequence< i ... > )
    { return {{ i + 1 ... }}; }
constexpr
std::array< int, 100 > upto_100() = make_upto_100( make_index_sequence< 100 >{} );

如果您真的在编译时间进行此操作。您可以使用integer_sequencestd::array

进行操作
#include <utility>
#include <array>
template <int... Is> // when called below, Is will be 0 - N
constexpr std::array<int, sizeof...(Is)> make_inc_array_impl(
    std::integer_sequence<int, Is...>) {
  return {{(Is + 1)...}}; // +1 to start at one instead of [0, 1, ...]
}

template <std::size_t N>
constexpr std::array<int, N> make_inc_array() {
  return make_inc_array_impl(std::make_integer_sequence<int, N>{});
}

然后打电话给您的大小

constexpr auto a = make_inc_array<100>(); // [1, 2, ..., 100]

这比列表理解的灵活性要小得多,只要使用std::iota并在运行时初始化您可能会更好。

好吧,这不是编译时间,但通常,我希望大多数代码都使用std::iota。在某些情况下,这实际上可能比编译时魔术要快,因为编译时间阵列需要存储在可执行文件的.data段中;如果阵列足够大,则从.data中读取额外的磁盘页面可能比写入纯粹的记忆页面的额外磁盘最终可能会变慢。

简单用法将是:

int buf[100];
std::iota(&buf[0], &buf[100], 1);

坦率地说,我会从这里开始,只有在运行时初始化有验证的性能问题时才开始查看模板魔术。

这应该适用于C 14。它通过递归模板的实例来工作,以将所有值初始化为constexpr。您应该能够通过更改模板参数将顺序值的大小更改为所需的任何内容。注意对于非常大的阵列,它可能会达到递归限制:

#include <array>
template<int NumVal, int ArrSize>
constexpr void setVal(std::array<int, ArrSize> &constArr) {
        std::get<NumVal>(constArr) = NumVal + 1;
        if(NumVal) setVal<NumVal ? NumVal - 1 : 0, ArrSize>(constArr);
}
template<int ArrSize>
constexpr auto arrRange() -> std::array<int, ArrSize> {
        std::array<int, ArrSize> tmp{};
        setVal<ArrSize - 1, ArrSize>(tmp);
        return tmp;
}
constexpr std::array<int, 100> constArr = arrRange<100>();
int main() {
        for(int itr = 0; itr < 100; ++itr) printf("%d ", constArr[itr]);
}

最新更新