首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在编译时使用Constexpr填充数组

在编译时使用Constexpr填充数组
EN

Stack Overflow用户
提问于 2012-11-10 02:38:41
回答 4查看 18.7K关注 0票数 23

我想使用constexpr填充一个枚举数组。数组的内容遵循一定的模式。

我有一个枚举,将ASCII字符集分为四类。

代码语言:javascript
复制
enum Type {
    Alphabet,
    Number,
    Symbol,
    Other,
};

constexpr Type table[128] = /* blah blah */;

我想要一个128个Type的数组。它们可以在一个结构中。数组的索引将对应于ASCII字符,值将是每个字符的Type

所以我可以查询这个数组来找出一个ASCII字符属于哪个类别。就像这样

代码语言:javascript
复制
char c = RandomFunction();
if (table[c] == Alphabet) 
    DoSomething();

我想知道,如果没有一些冗长的宏技巧,这是否可能。

目前,我通过执行以下操作来初始化表。

代码语言:javascript
复制
constexpr bool IsAlphabet (char c) {
    return ((c >= 0x41 && c <= 0x5A) ||
            (c >= 0x61 && c <= 0x7A));
}

constexpr bool IsNumber (char c) { /* blah blah */ }

constexpr bool IsSymbol (char c) { /* blah blah */ }

constexpr Type whichCategory (char c) { /* blah blah */ }

constexpr Type table[128] = { INITIALIZE };

其中INITIALIZE是一些非常冗长的宏黑客的入口点。就像这样

代码语言:javascript
复制
#define INITIALIZE INIT(0)
#define INIT(N) INIT_##N
#define INIT_0 whichCategory(0), INIT_1
#define INIT_1 whichCategory(1), INIT_2
//...
#define INIT_127 whichCategory(127)

我想要一种方法来填充这个数组或一个包含该数组的结构,而不需要这个宏黑...

也许是像这样的

代码语言:javascript
复制
struct Table {
    Type _[128];
};

constexpr Table table = MagicFunction();

因此,问题是如何编写此MagicFunction

注意:我知道cctype和likes,这个问题更像是一个Is this possible?而不是Is this the best way to do it?

任何帮助都将不胜感激。

谢谢,

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2012-11-10 04:55:54

忽略所有问题,indices提供了解决方案:

代码语言:javascript
复制
template<unsigned... Is> struct seq{};
template<unsigned N, unsigned... Is>
struct gen_seq : gen_seq<N-1, N-1, Is...>{};
template<unsigned... Is>
struct gen_seq<0, Is...> : seq<Is...>{};

template<unsigned... Is>
constexpr Table MagicFunction(seq<Is...>){
  return {{ whichCategory(Is)... }};
}

constexpr Table MagicFunction(){
  return MagicFunction(gen_seq<128>{});
}

Live example.

票数 30
EN

Stack Overflow用户

发布于 2017-10-17 05:44:37

在C++17中,::std::array已经更新为对constexpr更友好,你可以像在C++14中一样做同样的事情,但在关键的地方没有一些可怕的外观黑客来绕过constexpr的缺失。下面是代码的样子:

代码语言:javascript
复制
#include <array>

enum Type {
    Alphabet,
    Number,
    Symbol,
    Other,
};

constexpr ::std::array<Type, 128> MagicFunction()
{
   using result_t = ::std::array<Type, 128>;
   result_t result = {Other};
   result[65] = Alphabet;
   //....
   return result;
}

const ::std::array<Type, 128> table = MagicFunction();

同样,MagicFunction仍然需要遵守相当宽松的constexpr规则。主要是,它不能修改任何全局变量或使用new (这意味着修改全局状态,即堆)或其他类似的东西。

票数 14
EN

Stack Overflow用户

发布于 2012-11-10 05:12:11

我想最好的方法就是编写一个很小的安装程序,它会为你生成table。然后,您可以丢弃安装程序,或者将其与生成的源代码一起签入。

这个问题的棘手部分就是这个问题的复制品:Is it possible to create and initialize an array of values using template metaprogramming?

诀窍是,不可能写出像这样的东西

代码语言:javascript
复制
Type table[256] = some_expression();

在文件范围内,因为全局数组只能使用文字(源代码级别)初始化器列表进行初始化。您不能使用constexpr函数的结果初始化全局数组,即使您可以通过某种方式让该函数返回一个std::initializer_list,但您不能这样做,因为它的构造函数没有声明为constexpr

因此,您需要做的就是让编译器为您生成数组,方法是使其成为模板类的static const数据成员。在我写不出的一两层元编程之后,您将在一行代码中找到底部,如下所示

代码语言:javascript
复制
template <int... Indices>
Type DummyStruct<Indices...>::table[] = { whichCategory(Indices)... };

其中,Indices是一个类似于0,1,2,... 254,255的参数包。您可以使用递归助手模板构造该参数包,也可以使用Boost中的内容。然后你就可以写

代码语言:javascript
复制
constexpr Type (&table)[] = IndexHelperTemplate<256>::table;

...But,当表格只有256个条目,除非ASCII码本身改变,否则它们永远不会改变,你为什么要这么做?正确的方法是最简单的方法:预计算所有256个条目并显式写出表,不需要模板、常量表达式或任何其他魔术。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13313980

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档