簡體   English   中英

將值的編譯時列表傳遞給 function 的最佳方法?

[英]Best way to pass compile-time list of values to function?

我試圖找到將值的編譯時列表傳遞給實用程序 function 的最佳方法,作為基於實際用例的練習。 該列表將進行一系列操作,結果值將用於運行時的另一個操作。 以下是我找到的一些解決方案,簡化為 MWE。

當然,實際用例中的操作要復雜得多,因此需要這些實用功能。

方案一:參數包

template <int number>
constexpr int sum() {
    return number;
}

template <int number, int next, int... rest>
constexpr int sum() {
    return number + sum<next, rest...>();
}

//API:

template <int... numbers>
inline void add(int& target) {
    target += sum<numbers...>();
}
...
int number = 0;
add<1, 2, 3, 4, 5>(number);

優點

  • 清潔 API
  • 僅需要 c++14

缺點

  • 帶有遞歸的笨重實現,當操作復雜時設計和閱讀起來很痛苦

解決方案 2: std::array

template <size_t N, std::array<int, N> numbers>
constexpr int sum() {
    int ret = 0;
    for (int number : numbers)
        ret += number;
    return ret;
}

//API:

template <size_t N, std::array<int, N> numbers>
inline void add(int& target) {
    target += sum<N, numbers>();
}
...
int number = 0;
add<5, std::array{1, 2, 3, 4, 5}>(number);

優點

  • 簡潔易讀的實現,無論操作多么復雜,都易於設計

缺點

  • 超級笨重的 API,列表的大小必須單獨指定
  • 需要 c++20 才能將內聯std::array作為非類型模板參數傳遞

解決方案 3: std::array包裝器

template <size_t N>
struct IntArray {
    constexpr IntArray(std::array<int, N> arr_) : arr(arr_) {}
    const std::array<int, N> arr;
};

template <IntArray numbers>
constexpr int sum() {
    int ret = 0;
    for (int number : numbers.arr)
        ret += number;
    return ret;
}

//API:

template <IntArray numbers>
inline void add(int& target) {
    target += sum<numbers>();
}
...
int target = 0;
add<IntArray<5>({1, 2, 3, 4, 5})>(target);

優點

  • 簡潔易讀的實現,無論操作多么復雜,都易於設計

缺點

  • (可以說)更少但仍然笨重 API,列表的大小必須單獨指定
  • 需要 c++20 能夠將內聯IntArray作為非類型模板參數傳遞,並且還能夠在至少 function 定義中省略IntArray模板參數值

解決方案 4: std::initializer_list

template <std::initializer_list<int> numbers>
constexpr int sum() {
    int ret = 0;
    for (int number : numbers)
        ret += number;
    return ret;
}

template <std::initializer_list<int> numbers>
inline void add(int& target) {
    target += sum<numbers>();
}
...
int target = 0;
add<{1, 2, 3, 4, 5}>(target);

優點

  • 簡潔易讀的實現,無論操作多么復雜,都易於設計
  • 干凈、可用和可讀 API

缺點

  • 不實際編譯(g++ 10.3.0 與gnu++2a ): 'std::initializer_list<int>' is not a valid type for a template non-type parameter because it is not structural

說實話,我不知道“非結構性”是什么意思。 考慮到std::initializer_list顯然完全是constexpr並且std::array在相同的情況下工作,我實際上對這種方法不起作用這一事實感到驚訝和失望。 標准中似乎有一個關於std::initializer_list字面性的錯誤: https://stackoverflow.com/a/28115954/1525238無論如何,我確實認為這是一些非常酷的編譯的錯失機會-時間魔法。

問題:

您能否提出以任何可能的方式改進上述解決方案的任何方法,或提出其他解決方案? 理想情況下,“最佳”解決方案將結合所有 API 和實施清潔度和可讀性,同時要求盡可能低的 c++ 標准。

感謝 HolyBlackCat 建議從包中初始化一個std::array ,我不知道這是可能的:

template <int... numbers>
constexpr int sum() {
    std::array<int, sizeof...(numbers)> arr = {numbers...};
    int ret = 0;
    for(int number : arr)
        ret += number;
    return ret;
}

//API:

template <int... numbers>
inline void add(int& target) {
    target += sum<numbers...>();
}
...
int number = 0;
add<1, 2, 3, 4, 5>(number);

這使得實現更加簡潔。 需要 c++17。

為什么不直接使用 initializer_list 參數呢?

constexpr int sum(std::initializer_list<int> numbers) {
    int ret = 0;
    for (int number : numbers)
        ret += number;
    return ret;
}

int target = sum({1, 2, 3, 4, 5});

暫無
暫無

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

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