c++ - 将编译时定义大小的数组初始化为常量表达式

标签 c++ arrays c++11 c++14

我有一个必须分配一次的字符串数组,它们的底层 c_str 必须在程序的整个持续时间内保持有效。

有一些 API 可提供有关某些任意数据类型的信息。可能看起来像这样:

// Defined outside my code
#define NUMBER_OF_TYPES 23
const char* getTypeSuffix(int index);

getTypeSuffix 不是 constexpr,因此它必须至少在运行时部分起作用。

必须提供的接口(interface):

// Returned pointer must statically allocated (not on stack, not malloc)
const char* getReadableTypeName(int type);

现在我的数组应该有以下类型:

std::string typeNames[NUMBER_OF_TYPES];

为了我的目的,它将在包装类中初始化,就在构造函数中:

class MyNames
{
  MyNames()
  {
    for (int i = 0; i < NUMBER_OF_TYPES; ++i)
    {
      names[i] = std::string("Type ") + getTypeSuffix(i);
    }
  }

  const char* operator[](int type) { return _names[(int)type].c_str(); }

private:
  std::string _names[NUMBER_OF_TYPES];
};

然后以单例方式使用它,例如:

const char* getReadableTypeName(int type) 
{
  static MyNames names;
  return names[type];
}

现在我想改进的是,我可以看到构造函数中的 for 循环可以这样替换:

 MyNames() : _names{std::string("Type ") + getTypeSuffix(0), std::string("Type ") + getTypeSuffix(1), ... , std::string("Type ") + getTypeSuffix(NUMBER_OF_TYPES-1)}
 {}

显然是一个伪代码,但你明白了——数组可以直接初始化,让构造函数没有主体,这很整洁。这也意味着数组成员 _names 可以是 const,进一步强制正确使用此辅助类。

我很确定在编译时通过表达式填充数组还有很多其他用途,而不是循环。我什至怀疑这是 03 期间发生的事情。

有没有一种方法可以编写具有灵活长度并由表达式定义的 C++11 样式数组初始值设定项列表?另一个简单的例子是:

constexpr int numberCount = 10;
std::string numbers[] = {std::to_string(1), std::to_string(2), ... , std::to_string(numberCount)};

同样,表达式而不是循环。

我问这个问题不是因为我想大幅提高性能,而是因为我想了解 C++14 及更高版本的新的、简洁的特性。

最佳答案

而不是 C 数组使用 std::array,然后你可以编写你的函数来返回那个 std::array 然后你的成员可以是 常量:

std::array<std::string, NUMBER_OF_TYPES> build_names()
{
    std::array<std::string, NUMBER_OF_TYPES> names;
    for (int i = 0; i < NUMBER_OF_TYPES; ++i)
    {
          names[i] = std::string("Type ") + getTypeSuffix(i);
    }
    return names;
}


class MyNames
{
  MyNames() : _names(build_names()) {}
  const char* operator[](int type) const { return _names[(int)type].c_str(); }

private:
  const std::array<std::string, NUMBER_OF_TYPES> _names;
};

现在你有了 std::array,你可以使用可变参数模板而不是循环,比如 (std::index_sequence stuff is C++14, but can在 C++11 中实现):

template <std::size_t ... Is> 
std::array<std::string, sizeof...(Is)> build_names(std::index_sequence<Is...>)
{
     return {{ std::string("Type ") + getTypeSuffix(i) }};
}

然后调用它:

MyNames() : _names(build_names(std::make_index_sequence<NUMBER_OF_TYPES>())) {}

关于c++ - 将编译时定义大小的数组初始化为常量表达式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56481048/

相关文章:

c++ - 通过 Post 数据接收到的 Un-Escape 字符串

sql - 简单的正则表达式来过滤掉前缀和后缀字符

c++ - 没有额外的实例方法和变量的对象切片

c++ - 将 lambda 传递给 std::thread 并调用类方法

c++ - 在容器中查找元素的标准化方法?

c++ - 在 SQL Server 表中进行更改时通知 C++ 应用程序

C++,无法从so库访问包含的头文件

C# 为什么在随机数中得到一个零数

java - Java 中的通用 vector

c++ - 我无法通过引用捕获传递 lambda