【问题标题】:generating table that indicates position of nth 1 bit in a byte at compile time生成表,指示编译时字节中第 n 个 1 位的位置
【发布时间】:2016-12-19 19:55:23
【问题描述】:

我试图弄清楚如何在 C++ (C++11) 的编译时生成一组预先计算的值。

数组被声明为unsigned char precalcalated_positions[256][8],对于precalcalated_positions[x][y],给出从字节值x的右边开始计数的y+1'th 1位的位位置(0-7),如果有则给出数字8 x 中没有那么多 1 位

因此,例如数组条目 precalculated_positions[51][2] 将是 4,因为 51 = 00110011 在二进制中,并且从右边的第三 (2+1) 1 位等于 1

虽然我可以很容易地编写一个程序来生成这个数组的源代码,但我想知道编译器本身是否有可能在编译时生成这个数组,也许是通过使用一些聪明的模板元编程和一些 constexpr 函数?

在运行时生成表(未优化)的代码如下:

int calculate_index(unsigned char c,unsigned char pos)
{
    int mask = 1;
    for(int i=0;i<8;i++) {
        if (c&mask) {
            if (pos==0) {
                return i;
            } else {
                pos--;
            }
        }
        mask<<=1;
    }
    return 8;
}
void generate_table() {
   for(int i=0;i<256;i++) for(int j=0;j<8;j++) {
      precalulated_positions[i][j] = calculate_index(i,j);
   }
}

诚挚感谢任何帮助,但请注意,这仅适用于 C++11。出于我的目的,我不能使用 C++14 的新构造。

如果有任何不清楚的地方,请询问,我会在必要时尝试进一步详细说明。

【问题讨论】:

  • 您是否真的尝试过编写在运行时执行此操作的代码?如果是这样,发布它可能会让更多人回答。
  • 感谢您的反馈。我添加了在运行时生成表的代码。
  • 你有机会使用 c++14 吗?如果是这样,那么我认为您可以将这些函数标记为 constexpr 并收工。
  • 不......不幸的是我不能。但是即使函数 calculate_index 被设为 constexpr (它可能是,即使对于 C++11,我只是还没有弄清楚如何),它仍然不会在编译时生成表,我仍然必须调用该函数。当然,我可以在运行时调用generate_table 一次,然后就使用该数组,但我想知道编译器是否可以为我生成该数组。
  • 事实证明,为该问题提出 C++11 解决方案颇具挑战性,但仍然很有趣!

标签: arrays c++11 compile-time


【解决方案1】:

所以,我没有意识到你不能使用 C++14。我想出了另一个仅使用 C++11 的解决方案。我在下面留下了 C++14 代码。

我将您的算法转换为递归版本(以适应 constexpr 函数),并使用模板参数包来填充表格。

template<int... Is>
struct Seq {};
template<int N, int... Is>
struct Gen : Gen<N-1, N-1, Is...> {};
template<int... Is>
struct Gen<0, Is...> : Seq<Is...> {};

constexpr auto computePosition(int c, int bit, int pos = 0) -> unsigned char {
    return pos == 8 ?
        8 :
        (c & (1 << pos)) == 0 ?
            computePosition(c, bit, pos+1) :
            bit == 0 ?
                pos :
                computePosition(c, bit-1, pos+1);
}

template<int c, int... Is>
constexpr auto generatePositions(Seq<Is...>) -> std::array<unsigned char, 8> {
    return {{ computePosition(c, Is)... }};
}

template<int c>
constexpr auto generatePositions() -> std::array<unsigned char, 8> {
    return generatePositions<c>(Gen<8>{});
}

template<int... Is>
constexpr auto generateTable(Seq<Is...>) -> std::array<std::array<unsigned char, 8>, 256> {
    return {{ generatePositions<Is>()... }};
}

constexpr auto generateTable() -> std::array<std::array<unsigned char, 8>, 256> {
    return generateTable(Gen<256>{});
}

Live example

C++14 版本:

struct Table {
    constexpr Table() : positions() {
        for (auto c = 0; c < 256; ++c) {
            for (auto i = 0; i < 8; ++i) {
                int mask = 1;
                auto pos = -1;
                auto bit = i;
                while (pos < 8 && bit >= 0) {
                    if (c & mask) {
                        --bit;
                    }
                    ++pos;
                    mask <<= 1;
                }
                positions[c][i] = pos;
            }
        }
    }

    unsigned char positions[256][8];
};

int main()
{
    constexpr auto precalculated_positions = Table();
    static_assert(precalculated_positions.positions[51][2] == 4, "wrong");
}

值位于Table 类型的任何变量的positions 字段中。

Live example

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-08-06
    • 1970-01-01
    • 2022-01-06
    • 1970-01-01
    • 2015-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多