constexpr 函数内的静态表

aki*_*kim 5 c++ constexpr c++17

我有一段将整数映射到整数的生成代码,其核心是一个简单的表。在 C++17 之前,它曾经是这样的:

int convert (int v)
{
  static const int table[] = { 3, 2, 6, 1, 7, 1, 6, 8 };

  if (0 <= v && v < sizeof table / sizeof table[0])
    return table[v];
  else
    return -1;
}
Run Code Online (Sandbox Code Playgroud)

使用 C++17,我想使用 constexpr。我预计增加constexpr的函数签名就足够了,但我要删除static表,这让我实施显然没有很好的理由更加复杂。没有太多提及,table在非constexpr情况下很可能会在堆栈上,所以我想我应该更换 staticconstexpr

G++ 8 报告:

/tmp/foo.cc: In function 'constexpr int convert(int)':
/tmp/foo.cc:14:26: error: 'table' declared 'static' in 'constexpr' function
   static const int table[] = { 3, 2, 6, 1, 7, 1, 6, 8 };
                          ^
Run Code Online (Sandbox Code Playgroud)

和 Clang++ 7:

/tmp/foo.cc:14:20: error: static variable not permitted in a constexpr function
  static const int table[] = { 3, 2, 6, 1, 7, 1, 6, 8 };
                   ^
1 error generated.
Run Code Online (Sandbox Code Playgroud)

由于我希望这段代码适用于所有 C++ 标准(并在每种情况下做正确的事情),我想我必须写这个(是的,宏,这不是问题):

#if 201703L <= __cplusplus
# define CONSTEXPR constexpr
# define STATIC_ASSERT static_assert
# define STATIC_OR_CONSTEXPR constexpr
#else
# include <cassert>
# define CONSTEXPR
# define STATIC_ASSERT assert
# define STATIC_OR_CONSTEXPR static
#endif

CONSTEXPR int convert (int v)
{
  STATIC_OR_CONSTEXPR const int table[] = { 3, 2, 6, 1, 7, 1, 6, 8 };

  if (0 <= v && v < sizeof table / sizeof table[0])
    return table[v];
  else
    return -1;
}

int main()
{
  STATIC_ASSERT(convert(-42) == -1);
  STATIC_ASSERT(convert(2) == 6);
  STATIC_ASSERT(convert(7) == 8);
  STATIC_ASSERT(convert(8) == -1);
}
Run Code Online (Sandbox Code Playgroud)

所以:

  • 是什么促使禁止在 constexpr 函数中使用静态存储变量?

  • 有没有我可能错过的更清洁的替代品?当然,我可以table退出convert,但我想避免这种情况。

  • 标准是否保证非 constexpr 上下文中 constexpr 函数中的 const 数组将在静态存储中而不是堆栈中?

Jar*_*d42 1

  • 有没有我可能错过的更清洁的替代方案?当然,我可以将表格从转换中取出,但我想避免这种情况。

怎么样(兼容C++11):

template <int... Ns>
struct MyTable
{
    static constexpr int get(std::size_t v)
    {
        return v < sizeof...(Ns) ? data[v] : -1;
    }

    static constexpr int data[] = {Ns...};  
};

constexpr int convert (std::size_t v)
{
    using table = MyTable<3, 2, 6, 1, 7, 1, 6, 8>;

    return table::get(v);
}
Run Code Online (Sandbox Code Playgroud)

演示

  • 标准是否保证非 constexpr 上下文中的 constexpr 函数中的 const 数组将位于静态存储而不是堆栈中?

我认为 constexpr 变量不需要具体化,将代码转换为 switch (或完美哈希)似乎是有效的实现。

所以我认为没有保证。