簡體   English   中英

總結std :: integer_sequence中的元素

[英]Summing up the elements in a std::integer_sequence

出於教育目的,我嘗試創建一個std::integer_sequence並將其元素匯總為參數包。 我希望這很簡單,並在下面編寫了代碼。

步驟1:創建了一組add()操作,以正確處理基於整數的均質參數包。 使用add<0,1,2,3>() call測試並正常工作。

步驟2:在這一步中,我想傳遞一個std::integer_sequence作為模板參數, std::integer_sequence和序列中的整數。 我失敗了,請參閱注釋掉的代碼。

如何傳遞std::integer_sequence作為模板參數?

一則錯誤消息是沒有函數模板總數的實例與該調用匹配。 為什么? 我期望一個整數序列等效於一個int參數包。

另一個錯誤消息說Args模板參數不是恆定的。 怎么可能 我希望這是一個后續錯誤,但是我在實驗中經常看到此錯誤組合。

我正在使用Microsoft VC ++ 2017編譯器。

#include <iostream>
#include <utility>

template <typename T>
T add(T first) {
    return first;
}

template <typename T, typename ... Args>
T add(T car, Args... cdr) {
    return car + add(cdr...);
}

template <int ... Args>
int total() {
    return add(Args...);
}


int main(int argc, char** argv)
{
    using std::cout;
    using std::endl;

    int s1 = 
        total<0, 1, 2, 3>();
    std::cout << "s1 = " << s1 << std::endl;

    // The following does not compile:
#if 0
    int s2 = 
        total<std::make_integer_sequence<int, 4>>();
    std::cout << "s2 = " << s2 << std::endl;

    static_assert(s1 == s2, "no match");
#endif

    // This should work:
    //
    {
        cout << typeid(std::make_integer_sequence<int, 4>()).name() << endl;;
        cout << std::make_integer_sequence<int, 4>().size << endl;;
    }

    return 0;
}

...后來,經過了很多有用的評論。 我學到了很多東西,現在有了以下工作代碼:

#include <iostream>
#include <utility>

template <typename T>
constexpr T add(T first) {
    return first;
}

template <typename T, typename ... Args>
constexpr T add(T car, Args... cdr) {
    return car + add(cdr...);
}

template <int ... Args>
constexpr int total() {
    return add(Args...);
}

template<int... Args>
constexpr int total(std::integer_sequence<int, Args...>) {
    return total<Args...>();
}

int main(int argc, char** argv)
{
    using std::cout;
    using std::endl;

    constexpr int s1 =
        total<0, 1, 2, 3>();
    std::cout << "s1 = " << s1 << std::endl;

    // The following now compiles. Oh, happy day!
#if 1
    constexpr int s2 =
        total(std::make_integer_sequence<int, 4> {});

    std::cout << "s2 = " << s2 << std::endl;

    static_assert(s1 == s2, "no match");
#endif

    // This should work:
    //
    {
        cout << typeid(std::make_integer_sequence<int, 4>()).name() << endl;;
        cout << std::make_integer_sequence<int, 4>().size << endl;;
    }

    return 0;
}

使用折疊表達式會容易得多:

template<class T, T... Args>
constexpr T total(std::integer_sequence<T, Args...> = {}) {
    return (Args + ...);
}

int main() {
    int s2 = 
        total(std::make_integer_sequence<int, 4>{});
    // Or calling directly
    int s1 = total<int, 0, 1, 2, 3>();
}

請注意默認的std::integer_sequence參數,因此,如果傳遞整數序列,它將推導Args參數。

如果您希望能夠在模板中使用std::integer_sequence類型進行調用,只需創建一個輔助函數即可:

template<class IntegerSequence>
constexpr auto total_of(IntegerSequence argument = {}) {
    return total(argument);  // Will deduce `T` and `Args`
}

total_of<std::make_integer_sequence<int, 4>>();

我期望一個整數序列等效於一個int參數包。

它不是: std::integer_sequence是一種類型; 所以

total<std::make_integer_sequence<int, 4>>();

可以匹配接收類型的模板total()函數

template <typename T>
int total ()
 { return ???; }

問題是從類型T您不能輕易提取整數序列。

如何傳遞std :: integer_sequence作為模板參數?

解決方案(嗯...一個可能的解決方案)是局部專業化。

不幸的是,一個函數不能是部分專用的。

但是,如果total是一個struct (或class ),則所有內容都是不同的。

您可以編寫total如下

template <typename>
struct total;

template <typename T, T ... Is>
struct total<std::integer_sequence<T, Is...>>
   : public std::integral_constant<T, (Is + ...)>
 { };

因此您可以通過以下方式使用它

constexpr auto s2 { total<std::make_integer_sequence<int, 4>>::value };

主題外:聲明constexpr要在static_assert()測試中使用的變量。

以下是完整的C ++ 17示例(將total結構重命名為total2以避免與total()函數沖突)

#include <utility>

template <typename>
struct total2;

template <typename T, T ... Is>
struct total2<std::integer_sequence<T, Is...>>
   : public std::integral_constant<T, (Is + ...)>
 { };

template <typename T>
constexpr T add (T first)
 { return first;}

template <typename T, typename ... Args>
constexpr T add (T car, Args ... cdr)
 { return car + add(cdr...); }

template <int ... Args>
constexpr int total ()
 { return add(Args...); }

int main ()
 {
   constexpr auto s1 { total<0, 1, 2, 3>() };
   constexpr auto s2 { total2<std::make_integer_sequence<int, 4>>::value };

   static_assert(s1 == s2);
 }

一種方法是為total增加一個重載,並以不同的方式調用它:

template<int... Args>
int total(std::integer_sequence<int, Args...> ) {
    return add(Args...);
}

比打電話

nt s2 = 
    total(std::make_integer_sequence<int, 4>>{});

這將解決呼叫問題。 為了在static_assert使用函數的結果,還需要確保將其(以及存儲其結果的變量)標記為constexpr

我期望一個整數序列等效於一個int參數包。

但是您可以通過寫出以下兩個擴展來看到它:

template <int ... Args> int total();

第一種情況是

total<0, 1, 2, 3>();
// => Args... is (0, 1, 2, 3)

這是一個有效的整數包,第二個是

total<std::make_integer_sequence<int, 4>>();
// => Args... must be std::integer_sequence<int, 0, 1, 2, 3>

這顯然不像整數包。 鏈接到std::integer_sequence的文檔以供參考。

如果要將整數序列轉換回傳遞給make_integer_sequence的原始參數包,則需要使用模板參數推導重載SergeyA的答案顯示:

template<int... Args>
int total(std::integer_sequence<int, Args...> ) {
    return add(Args...);
}

(函數參數是一個虛擬變量,僅用於推導Args... )。

但是,如果可以使用fold表達式,則它比老式的遞歸要好得多。

暫無
暫無

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

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