以编译方式在C++中编译时创建静态数组

Hip*_*der 63 c++ metaprogramming static-array

可以在编译时定义静态数组,如下所示:

const std::size_t size = 5;    
unsigned int list[size] = { 1, 2, 3, 4, 5 };
Run Code Online (Sandbox Code Playgroud)

问题1 - 是否可以通过使用各种元编程技术在编译时"以编程方式"分配这些值?

问题2 - 假设数组中的所有值都是相同的barr,是否可以在编译时以编程方式选择性地分配值?

例如:

const std::size_t size = 7;        
unsigned int list[size] = { 0, 0, 2, 3, 0, 0, 0 };
Run Code Online (Sandbox Code Playgroud)
  1. 欢迎使用C++ 0x的解决方案
  2. 阵列可能非常大,几百个元素长
  3. 现在的数组只包含POD类型
  4. 还可以假设,以静态编译时兼容的方式预先知道阵列的大小.
  5. 解决方案必须是C++ (没有脚本,没有宏,没有pp或基于代码生成器的解决方案)

更新: Georg Fritzsche的解决方案非常棒,需要一些工作才能在msvc和intel编译器上进行编译,但这仍然是解决问题的一种非常有趣的方法.

Geo*_*che 78

您可以获得的最接近的是使用C++ 0x功能从可变参数模板参数列表初始化模板的本地或成员数组.
这当然受到最大模板实例化深度的限制,并且必须测量实际上在您的情况下显着差异.

例:

template<unsigned... args> struct ArrayHolder {
    static const unsigned data[sizeof...(args)];
};

template<unsigned... args> 
const unsigned ArrayHolder<args...>::data[sizeof...(args)] = { args... };

template<size_t N, template<size_t> class F, unsigned... args> 
struct generate_array_impl {
    typedef typename generate_array_impl<N-1, F, F<N>::value, args...>::result result;
};

template<template<size_t> class F, unsigned... args> 
struct generate_array_impl<0, F, args...> {
    typedef ArrayHolder<F<0>::value, args...> result;
};

template<size_t N, template<size_t> class F> 
struct generate_array {
    typedef typename generate_array_impl<N-1, F>::result result;
};
Run Code Online (Sandbox Code Playgroud)

适用于您的1..5情况:

template<size_t index> struct MetaFunc { 
    enum { value = index + 1 }; 
};

void test() {
    const size_t count = 5;
    typedef generate_array<count, MetaFunc>::result A;

    for (size_t i=0; i<count; ++i) 
        std::cout << A::data[i] << "\n";
}
Run Code Online (Sandbox Code Playgroud)

  • 非常非常棒! (3认同)
  • 关于模板实例化深度的注释,msvc在1000左右死亡,gcc有一个设置递归深度的选项,我已经能够用这个建议创建一个512元素lut - 编译时间显然比让lut硬得多一点 - 在源代码中编码,但总体而言它工作得很好!!! :d (2认同)
  • 作为一些编译器允许的相当有限的递归深度的解决方法,可以向每个步骤的"可变参数值列表"添加多于一个值,减少所需的深度M次,其中M是添加的值的数量.例如,对于M = 2,我们有:template <size_t N,template <size_t> class F,unsigned ... args> struct generate_array_impl {typedef typename generate_array_impl <N-2,F,F <N-1> :: value ,F <N> :: value,args ...> ::结果结果; }; 但请不要忘记处理N%M!= 0的情况 (2认同)

Mat*_* M. 6

那么你的要求是如此模糊,很难对它们采取任何行动......主要问题当然是:这些价值来自哪里?

无论如何,C++中的构建可以被认为是4个步骤:

  • 预构建步骤:从其他格式生成头/源的脚本
  • 预处理
  • 模板实例化
  • 编译正确

如果您希望排除脚本生成,那么您将有两种选择:预处理和元模板编程.

我不知道元模板编程在这里可以做到这一点,因为据我所知,在编译时不可能连接两个数组.因此,我们留下了当时的救星:预处理程序编程

我建议使用一个完整的库来帮助我们:Boost.Preprocessor.

特别感兴趣的是:

现在,只要我们知道从哪里挑选价值,我们就可以给出更有意义的例子.

  • 查看Georg Fritzsche的答案:使用C++ 0x可变参数模板并从varadic列表初始化静态数组,他能够提出一个metatemplate解决方案! (3认同)

jan*_*b04 5

从 C++17 开始,您可以使用constexprlambda 并就地调用它。唯一的“缺点”是您必须使用std::array而不是 c 样式的数组:

constexpr auto myArray{[]() constexpr{
    std::array<MyType, MySize> result{};
    for (int i = 0; i < MySize; ++i)
    {
       result[i] = ...
    }
    return result;
}()};
Run Code Online (Sandbox Code Playgroud)

作为一个例子,你可以如何创建一个具有 2 次幂的数组:

constexpr auto myArray{[]() constexpr{
    constexpr size_t size = 64;
    std::array<long long, size> result{};
    result[0] = 1;
    for (int i = 1; i < size; ++i)
    {
       result[i] = result[i - 1] * 2;
    }
    return result;
}()};
Run Code Online (Sandbox Code Playgroud)

如您所见,您甚至可以引用数组的先前单元格。

这种技术称为 IILE 或立即调用 Lambda 表达式。