簡體   English   中英

將編譯時定義的數組初始化為常量表達式

[英]Initialize array of compile time defined size as constant expression

我有一個字符串數組,必須分配一次,它們的底層c_str必須在程序的整個持續時間內保持有效。

有一些API提供有關某些任意數據類型的信息。 看起來像這樣:

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

getTypeSuffix不是constexpr ,因此必須至少部分在運行時工作。

必須提供的界面:

// 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 ,然后你的成員可以是const

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 ,你可以使用variadic模板而不是loop,比如( std::index_sequence stuff是C ++ 14,但是可以在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>())) {}

您可以按照初始化函數:

std::array<std::string, NUMBER_OF_TYPES> initializeNames()
{
    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;
}

const char* getReadableTypeName(int type) 
{
  static auto const names = initializeNames();
  return names[type].c_str();
}

這可以是一個立即調用的lambda:

static auto const names = []{
    std::array<std::string, NUMBER_OF_TYPES> names;
    // ...
    return names;
}();

或者你真的需要array要求嗎? 無論如何我們正在制作字符串所以我不明白,那么你可以使用range-v3:

char const* getReadableTypeName(int type) {
    static auto const names =
        view::iota(0, NUMBER_OF_TYPES)
        | view::transform([](int i){ return "Type "s + getTypeSuffix(i); })
        | ranges::to<std::vector>();
    return names[type].c_str():
}

您可以在C ++ 14中使用std::make_integer_sequence和委托構造函數(C ++ 11中存在std::make_integer_sequence實現,因此這不是特定的C ++ 14)來獲取整數的模板參數包

#include <string>
#include <utility>

#define NUMBER_OF_TYPES 23

const char* getTypeSuffix(int index);

class MyNames
{
  MyNames() : MyNames(std::make_integer_sequence<int, NUMBER_OF_TYPES>{}) {}

  template<int... Indices>
  MyNames(std::integer_sequence<int, Indices...>) : _names{ (std::string("Type ") + getTypeSuffix(Indices))... } {}

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

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

這意味着沒有默認構造的字符串。

既然你想要使用新功能,那么讓我們使用range-v3 (即將成為C ++ 2a中的ranges庫)來編寫一些非常簡短的代碼:

const char* getReadableTypeName(int type) 
{
    static const std::vector<std::string> names =
        view::ints(0, 23) | view::transform([](int i) {
            return "Type " + std::to_string(i);
        });
    return names[type].c_str();
}

https://godbolt.org/z/UVoENh

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM