簡體   English   中英

使用 SFINAE 作為模板參數的編譯時遞歸

[英]Compile-time recursion with SFINAE as template argument

我在玩模板,我想用它們來編寫一個將在編譯時評估的遞歸函數。 我希望它根據我傳遞給它的數字進行分支。 該函數確實有一個約束; 我想保留返回值。

所以這是我嘗試編寫函數(它不編譯):

template<int n, typename std::enable_if_t<n==1>>
constexpr auto fun() { return std::make_tuple(1); }

template<int n, typename std::enable_if_t<n==2>>
constexpr auto fun() { return std::make_tuple(fun<1>(), 2); }

template<int n, typename enable = void>
constexpr auto fun() {
    return std::tuple_cat(fun<n-1>(), n);
}

int main() {
    constexpr auto x = fun<4>();

    return 0;
}

我面臨的問題是我不確定將std::enable_if_t語句放在哪里,以及如何准確地編寫它以確保我的函數正確分支。 我在這里缺少什么?

假設您想連接元組並以以下形式創建它

fun<4>() == tuple(1, 2, 3, 4);

你可以寫兩個模板,比如

template<int n, std::enable_if_t<n == 1>* = nullptr>
constexpr auto fun() 
{
    return std::make_tuple(1); 
}

template<int n, std::enable_if_t<n != 1>* = nullptr>
constexpr auto fun()
{
    return std::tuple_cat(fun<n-1>(), std::tuple(n));
}

但是,這不是執行此操作的“C++17 方式” 使用if constexpr可以更好地表達它

template<int n>
constexpr auto fun2()
{
    if constexpr (n > 1)
        return std::tuple_cat(fun2<n-1>(), std::tuple(n));
    else
        return std::tuple(1);
}

關於序列創建(例如1, 2, 3, 4, ... )還有std::integer_sequence可以與模板參數包結合使用

template <int... nums>
constexpr auto construct(std::integer_sequence<int, nums...>)
{
    return std::tuple((nums + 1)...);
}

template<int n>
constexpr auto fun3()
{
    return construct(std::make_integer_sequence<int, n>());
}

是一個完整的例子。

我不清楚你到底想要什么但是......讓我猜猜:你想要的東西如下

#include <tuple>
#include <type_traits>

template<int n, std::enable_if_t<n==1, bool> = true>
constexpr auto fun() { return std::make_tuple(1); }

template<int n, std::enable_if_t<n!=1, bool> = true>
constexpr auto fun() { return std::tuple_cat(fun<n-1>(), std::make_tuple(n)); }

int main() { constexpr auto x = fun<4>(); }

訣竅

template<int n, typename enable = void>

是模板類的 SFINAE 技巧,其中有主要版本和一些專業化; 所以主版本定義了通過std::enable_if啟用/禁用 SFINAE 的簽名和專業化。

使用函數,您可以重載函數,但不能進行部分專業化。 您必須單獨啟用/禁用每個重載功能

template<int n, std::enable_if_t<n==1, bool> = true>
// ...

template<int n, std::enable_if_t<n!=1, bool> = true>
// ...

注意我寫的

template<int n, std::enable_if_t<n==1, bool> = true>

並不是

template<int n, typename = std::enable_if_t<n==1>>

第二種形式也可用於啟用/禁用單個功能,但當您具有具有相同簽名的不同功能(如您的情況)並且您只想啟用一個版本時,則不起作用。

暫無
暫無

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

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