如何创建constexpr列表?

时间:2017-07-16 10:56:18

标签: c++ parsing c++14 constexpr

我正在编写一个编译时解析,创建列表的库。 我能够让它立即工作的唯一方法是使用我的Node结构的std :: array作为“静态分配的池”,并使用整数索引作为该指针的“指针”。

这很好用,但我不得不修改数组的大小。

这就是我所拥有的:

#include <iostream>
using namespace std;

struct Symbol
{
  constexpr Symbol(): pBeg(), pEnd() {}
  constexpr Symbol(const char *pBeg,  const char *pEnd): pBeg(pBeg), pEnd(pEnd) {}
  constexpr int len() { return pEnd - pBeg; }

  string getText() const { return string(pBeg, pEnd); }


  const char *pBeg;
  const char *pEnd;
};


extern void ParseError(const char *s) {cerr << "Parse Error:" << s << endl;}

constexpr bool isAlpha(char ch)
{
  return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'); 
}

// Raises compiletime error if no more characters left to parse
constexpr const char *checkEOS(const char *pszText)
{
  bool eos = !*pszText;
  if(eos) ParseError("Unexpected end of stream");

  return pszText;
}

// Takes a string literal and returns pointer to first non-whitespace character
constexpr const char *eatSpace(const char *pszText)
{
  while(*pszText == ' ' || *pszText == '\n' || *pszText == '\r' || *pszText == '\t')
  {
    ++pszText;
  }
  return pszText;
}

// Takes a string literal text and tries to consume [a-z]+
constexpr const Symbol eatAlpha(const char *pszText)
{
  // Ensure not EOS
  checkEOS(pszText);

  Symbol sym;
  sym.pBeg = pszText;
  sym.pEnd = pszText;
  while(isAlpha(*sym.pEnd)) sym.pEnd++;

  // Ensure at least 1 character is consumed
  bool empty_tag = sym.pBeg == sym.pEnd;
  if(empty_tag) ParseError("Expecting an identifier");

  return sym;
}

struct Node 
{
  Symbol tag;       // pointer to tag name range
  const Node &child;

  constexpr Node(Symbol tag, const Node child):tag(tag), child(child){}

};

constexpr const Symbol NullSym;
constexpr const Node NullNode{NullSym, NullNode};


constexpr Node parse(const char* text)
{
  if(text)
  {
    text = eatSpace(text);
    if(isAlpha(*text))
    {
      Symbol symTag = eatAlpha(text);
      return Node(symTag, parse(symTag.pEnd));
    }
  }
  return NullNode;
}

void dumpNode(const Node &n, int indent = 0)
{
  if(&n.child != &NullNode)
  {
    cerr << n.tag.getText() << endl;
    dumpNode(n.child, indent + 1);
  }
}


int main()
{
  constexpr Node node = parse("attr battr cattr");
  dumpNode(node);
}

编译时:

    $ g++ --std=c++14 -DSPT_DEBU main4.cpp
main4.cpp:72:48: error: 'Node{Symbol{0, 0}, child}' is not a constant expression
constexpr const Node NullNode{NullSym, NullNode};
                                                ^
main4.cpp: In function 'int main()':
main4.cpp:101:49:   in constexpr expansion of 'parse(((const char*)"attr battr cattr"))'
main4.cpp:83:44:   in constexpr expansion of 'parse(symTag.Symbol::pEnd)'
main4.cpp:83:44:   in constexpr expansion of 'parse(symTag.Symbol::pEnd)'
main4.cpp:83:44:   in constexpr expansion of 'parse(symTag.Symbol::pEnd)'
main4.cpp:101:49: error: constexpr call flows off the end of the function
  constexpr Node node = parse("attr battr cattr");
                                                ^

我正在尝试甚至可能吗?

当你通过递归调用嵌套时,我对constexpr值的生命周期有点模糊

我很确定这应该是可能的。毕竟有人写了一个constexpr C编译器。

我需要的是某种动态数据结构,如列表,在编译时不必修复大小。

提前致谢。

0 个答案:

没有答案