C ++ 14:如何使用可变参数模板创建值为1-100的数组

时间:2017-03-07 02:44:34

标签: c++ arrays templates list-comprehension variadic

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

但c ++ 11/14模板可以做到吗,怎么做? 感谢

4 个答案:

答案 0 :(得分:5)

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 >{} );

答案 1 :(得分:3)

如果您真的打算在编译时进行此操作。您可以使用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并在运行时初始化。

答案 2 :(得分: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]);
}

答案 3 :(得分:0)

嗯,它不是编译时间,但通常情况下,我希望大多数代码都使用std::iota。在某些情况下,这实际上可能比编译时魔术更快,因为编译时数组需要存储在可执行文件的.data段中;如果数组足够大,从.data读取额外的磁盘页面可能比写入从操作系统中删除的纯内存页面更慢。

简单的用法是:

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

坦率地说,我是从这里开始的,如果你在运行时初始化时遇到一个经证实的性能问题,那就开始考虑模板魔法了。