【问题标题】:C++ 14: How to use variadic template to create an array of values 1-100C++ 14:如何使用可变参数模板创建值 1-100 的数组
【发布时间】:2017-03-07 02:44:34
【问题描述】:

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

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

【问题讨论】:

  • 在全局命名空间中看不到这样做的方法,但这个数组可以声明为辅助类的静态成员。尽管如此,如果您的目标真的是简单地初始化一个int 数组,只需编写一个脚本来自动生成源代码,而不是乱用模板。如果您的目标是完成家庭作业,那么您的全部原因是您自己解决,而不是让 stackoverflow.com 上的其他人为您完成家庭作业。

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


【解决方案1】:

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

【讨论】:

  • @RyanHaining 已修复。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

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

    简单的用法是:

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

    坦率地说,我会从这里开始,如果您在运行时初始化方面存在经证实的性能问题,则只会开始研究模板魔法。

    【讨论】:

      【解决方案4】:

      这应该适用于 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]);
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-08-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-09-01
        • 2021-05-02
        相关资源
        最近更新 更多