English 中文(简体)
在C++的汇编时间形成静态阵列
原标题:Programmatically create static arrays at compile time in C++

在汇编时间可以确定静态阵列如下:

const std::size_t size = 5;    
unsigned int list[size] = { 1, 2, 3, 4, 5 };

Question 1 - 是否可能利用各种美术技术,在汇编时间分配这些价值“programically”?

< 问题2——假设阵列中的所有数值为少数,能否以方案方式在汇编时间有选择地分配价值?

指称:

const std::size_t size = 7;        
unsigned int list[size] = { 0, 0, 2, 3, 0, 0, 0 };
  1. Solutions using C++0x are welcome
  2. The array may be quite large, few hundred elements long
  3. The array for now will only consist of POD types
  4. It can also be assumed the size of the array will be known beforehand, in a static compile-time compliant manner.
  5. Solutions must be in C++ (no script, no macros, no pp or code generator based solutions pls)

<><>UPDATE: Georg Fritzsche的解决方案令人惊讶,需要做些什么工作,才能将其汇编成雕像和电视汇编者,但还是对这个问题非常有趣的做法。

最佳回答

The closest you can get is using C++0x features to initialize local or member arrays of templates from a variadic template argument list.
This is of course limited by the maximum template instantiation depth and wether that actually makes a notable difference in your case would have to be measured.

例:

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

使用<代码>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] << "
";
}
问题回答

由于C++17 ,你可以使用<条码>constexpr lambda 申请。 唯一的“下层”是,你必须使用<代码>std:array。 而不是像样阵列:

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

举一个例子,说明你如何能够建立具有两种权力的阵列:

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

你可以看到,你甚至可以提到前面的阵列。

这种技术称为二审或立即引用拉宾达语。

你们的要求非常模糊,很难对他们做任何事情。 主要问题是:这些价值来自何处?

在C++建造房屋的任何途径,可被视为4个步骤:

  • Pre-build steps: script generation of header/source from other formats
  • Preprocessing
  • Template instantiations
  • Compilation proper

如果你想排除文字生成,那么你就再留下了两种选择: 预处理和元件方案。

我根本不知道有哪一种办法可以在这里进行精心策划,因为就我所知,不可能在汇编时间召集两个阵列。 因此,我们留给了当天的星号:Preprocessor Program

我建议利用一个完整的图书馆来帮助我们:Boost.Preprocessor

特别值得注意的是:

现在,只有我们知道从哪里汲取价值观,我们才能提出更有意义的例子。

如何利用模板建造一个封顶的构件,并把它作为一系列正确的类型。 以下例子为我服务,但我感觉到,我要么在接近于不明确的行为时步行或步行。

#include <iostream>

template<int N>
struct NestedStruct
{
  NestedStruct<N-1> contained;
  int i;
  NestedStruct<N>() : i(N) {}
};

template<>
struct NestedStruct<0> 
{
  int i;
  NestedStruct<0>() : i(0) {}
};

int main()
{
  NestedStruct<10> f;
  int *array = reinterpret_cast<int*>(&f);
  for(unsigned int i=0;i<10;++i)
  {
    std::cout<<array[i]<<std::endl;
  }
}

当然,你可以辩称,这些阵列不是在汇编时间(我认为是不可能的)时开始的,而将纳入阵列的数值是在汇编时间时计算的,你可以查阅,因为你是正常阵列。 我认为,这同你一样接近。

只是使用一种代码生成器。 建立一个或多个模板,利用表格或甚至数学功能生成你想要的代码。 之后,请在您的信中提供你的文件。

很严重的是,制定法典将使你的生活更加容易。

Sometime (not always) such array is generated from array of types. For example if you already have variadic class list (like template) and want to store encapsulated uint32_t value you can use:

uint32_t tab[sizeof(A)]= {A::value...};

你们是否确实需要在汇编时这样做? 在静态初始化时,这样做将非常容易。 你可以这样做。

#include <cstddef>
#include <algorithm>

template<std::size_t n>
struct Sequence
{
    int list[n];

    Sequence()
    {
        for (std::size_t m = 0; m != n; ++m)
        {
            list[m] = m + 1;
        }
    }
};

const Sequence<5> seq1;

struct MostlyZero
{
    int list[5];

    MostlyZero()
    {
        std::fill_n(list, 5, 0); // Not actually necessary if our only
                                 // are static as static objects are
                                 // always zero-initialized before any
                                 // other initialization
        list[2] = 2;
        list[3] = 3;
    }
};

const MostlyZero mz1;

#include <iostream>
#include <ostream>

int main()
{
    for (std::size_t n = 0; n != 5; ++n)
    {
        std::cout << seq1.list[n] << ", " << mz1.list[n] <<  
 ;
    }
}

如果你想要的话,你可以把名单推到结构之外,但我认为这比这更清洁。

诸如Boost.Assignment 可以为标准集装箱工作。 如果你真的需要使用阵列,你可使用

页: 1 你可以这样做。

template <int num, int cur>
struct ConsequentListInternal {
    enum {value = cur};
    ConsequentListInternal<num-1,cur+1> next_elem;
};

template <int cur>
struct ConsequentListInternal<0, cur> {
    enum {value = cur};
};

template <int v>
struct ConsequentList {
    ConsequentListInternal<v, 0> list;
};

int main() {
    ConsequentList<15> list;
    return 0;
}

There s a lot of things you can do with meta-programming. But first I d like to ask: why would you want to do this in your case? I could understand if you needed to declare such an array in different places, so that it d demand rewriting the same things multiple times. Is this your case?

我在说“从方案角度看”时建议如下:

#define MyArr(macro, sep) 
    macro(0) sep 
    macro(0) sep 
    macro(2) sep 
    macro(3) sep 
    macro(0) sep 
    macro(0) sep 
    macro(0)

到现在,我们以最抽象的方式界定了你想要的所有价值观。 BTW 如果这些价值观实际上对你来说意味着什么,那么你可以在声明中添加:

#define MyArr(macro, sep) 
    macro(0, Something1) sep 
    macro(0, Something2) sep 
    // ...

我现在要把生命化为上述宣言。

#define NOP
#define COMMA ,
#define Macro_Count(num, descr) 1
#define Macro_Value(num, descr) num

const std::size_t size = MyArr(Macro_Count, +); 
unsigned int list[size] = { MyArr(Macro_Value, COMMA) };

你们还可以处理你大多数阵列条目相同的情况,有些vert的创造力:

但是,你们应该总是问:这是否真正值得? 因为,正如你所看到的那样,你把该守则变成了一种迷惑。

增减

boost::mpl::range_c<int,1,5>

在汇编时间时,将编制一份从1到5的分类数字清单。 第二,你没有提及改变价值的标准。 我确信,一旦制定一份名单,你就可以避免再 red。

使用模板

template<uint64_t N>
constexpr uint64_t Value()
{
    return N + 100;
}

// recursive case
template<uint64_t N, uint64_t... args>
struct Array : Array<N - 1, Value<N - 1>(), args...> {
};

// base case
template<uint64_t... args>
struct Array<0, Value<0>(), args...> {
    static std::array<uint64_t, sizeof...(args) + 1> data;
};

template<uint64_t... args>
std::array<uint64_t, sizeof...(args) + 1> Array<0, Value<0>(), args...>::data = {Value<0>(), args...};

int main()
{
    Array<10> myArray;
    for (size_t i = 0; i < myArray.data.size(); ++i) {
        cout << myArray.data[i] << endl;
    }

    return 0;
}

array<int, SIZE> t

如前所述,C++17 您可使用孔径。

vector<int> countBits(int num) {
    static constexpr int SIZE = 100000;
    static constexpr array<int, SIZE> t {[]() constexpr {
            constexpr uint32_t size = SIZE;
            array<int, size> v{};
            for (int i = 0; i < size; i++)
                v[i] =  v[i>>1] + (i & 1); // or simply v[i] = __builtin_popcount(i);
            return v;}()};

    vector<int> v(t.begin(), t.begin() + num + 1);
    return v;
}

然而,你必须使用++阵列类型。


int t[SIZE]

如果你真想使用一个C阵列int [SIZE],不同于array<int, SIZE>

宣布全球阵列,然后计算主体内的数值,以便在汇编时间建立静态阵列:

int w[100000] = {0};

vector<int> countBits(int num) {
    vector<int> v(w, w + num + 1);
    return v;
}

int main(void) {
    for (int i = 0; i < 100000; i++)
        w[i] = __builtin_popcount(i);
}


Results

运行时间的产出(确实是:)

OK  ( 591 cycles)        0,1,1, -> 0,1,1,
OK  ( 453 cycles)        0,1,1,2,1,2, -> 0,1,1,2,1,2,
OK  ( 455 cycles)        0,1,1,2,1,2,2,3,1,2,... -> 0,1,1,2,1,2,2,3,1,2,...

2. 与科斯特阵列的平均产出:

OK  (   1 cycles)        0,1,1, -> 0,1,1,
OK  (   2 cycles)        0,1,1,2,1,2, -> 0,1,1,2,1,2,
OK  (  24 cycles)        0,1,1,2,1,2,2,3,1,2,... -> 0,1,1,2,1,2,2,3,1,2,...

采用第二种方法的平均产出(在我们摆脱C++阵列的间接费用时,略为加快):

OK  (   0 cycles)        0,1,1, -> 0,1,1,
OK  (   1 cycles)        0,1,1,2,1,2, -> 0,1,1,2,1,2,
OK  (  23 cycles)        0,1,1,2,1,2,2,3,1,2,... -> 0,1,1,2,1,2,2,3,1,2,...

Benchmark

我的基准是:

#include <vector>
#include <string>
#include <cstdint>
#include <array>
#include <iostream>
#include <ctime>
#include <iterator>
#include <sstream>

using namespace std;

vector<int> nums = {2, 5};
vector<vector<int>> expected = {{0,1,1}, {0,1,1,2,1,2}}; // feel free to add more tests

for (int i = 0; i < expected.size(); i++) {
        clock_t start = clock();
        vector<int> res = countBits(nums[i]);
        double elapsedTime = (clock() - start);
        printf("%s  33[30m(%4.0lf cycles)33[0m	 %s -> %s
", (expected[i] == res) ? "33[34mOK" : "33[31mKO", elapsedTime, toString(res).c_str(), toString(expected[i]).c_str());
}

随着时间的推移,在C++中,<代码>constexpr功能、方法和lambdas的能力大大提高。 有了C++17,你可以在汇编时间实际计算<条码>constexpr阵列内容的条件。 See this example for a prime number sieve:

#include <array>
#include <cmath>

template<unsigned N>
constexpr auto primesieve() {
    std::array<bool, N+1> primes {};
    // From C++20, the init loop may be written as:   primes.fill(true);
    for(unsigned n = 0; n <= N; n++) {
        primes[n] = true;
    }
    unsigned maxs = sqrt(N);
    for(unsigned n = 2; n <= maxs; n++) {
        if(primes[n]) {
            for(unsigned j = n + n; j <= N; j += n) {
                primes[j] = false;
            }
        }
    }
    return primes;
};

extern constexpr std::array<bool, 20> myprimes { primesieve<19>() };

在研究该守则的组装产出时,你将只看到<代码>myprimes阵列的数据,而不是单项程序指示。 所有计算都是在汇编时间进行的,即使最佳化工作已经停止。

然而,正如其他人已经写的: 汇编者中C++代码的校正比汇编的C++代码要慢得多。 因此,这些初始化在汇编时间时可以合理地进行,在时间的多数情况下会耗尽。

const/constpr的初始化具有许多优势。 也就是说,他们不断记忆,这是在相同应用的不同过程之间分享的。 而另一方面,动态的初始化则在一段时间内传给每个进程的私人记忆。

这些能力正在进一步改善。 C++20甚至为<代码>std:string和std:vectorconstexpr中增加支持。 然而,您无法从<条码>constexpr/ 代码>功能中回收非发性方言和矢量,直到现在,只有微软的汇编商才采用了这一特征。





相关问题
Undefined reference

I m getting this linker error. I know a way around it, but it s bugging me because another part of the project s linking fine and it s designed almost identically. First, I have namespace LCD. Then I ...

C++ Equivalent of Tidy

Is there an equivalent to tidy for HTML code for C++? I have searched on the internet, but I find nothing but C++ wrappers for tidy, etc... I think the keyword tidy is what has me hung up. I am ...

Template Classes in C++ ... a required skill set?

I m new to C++ and am wondering how much time I should invest in learning how to implement template classes. Are they widely used in industry, or is this something I should move through quickly?

Print possible strings created from a Number

Given a 10 digit Telephone Number, we have to print all possible strings created from that. The mapping of the numbers is the one as exactly on a phone s keypad. i.e. for 1,0-> No Letter for 2->...

typedef ing STL wstring

Why is it when i do the following i get errors when relating to with wchar_t? namespace Foo { typedef std::wstring String; } Now i declare all my strings as Foo::String through out the program, ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

Window iconification status via Xlib

Is it possible to check with the means of pure X11/Xlib only whether the given window is iconified/minimized, and, if it is, how?

热门标签