簡體   English   中英

C ++僅擴展參數包的一部分

[英]C++ Expand only part of the parameter pack

前言

鑒於我有不同類型的N個參數(uint,int和float),並且每個參數都有自己的有效值范圍(即從2.5到20.0)。 還給出了一些參數來自其他參數。 對於那些參數,我使用不同的函數(f1,f2,f3,...)。

為了能夠計算派生參數的有效值范圍(最小值和最大值),我為每個派生參數定義了兩個新函數f_min和f_max。 在這些函數中,我使用min和max參數值的正確組合調用f來獲取派生參數的限制邊界。

我們舉一個簡單的例子:

f(a, b) = a / b
min = f(a_min, b_max)
max = f(a_max, b_min)

如何解決它

首先,我將所有最小和最大參數值存儲到兩個容器中。 然后我定義一個deriveLimit模板函數,它獲取模板參數作為指向函數的指針,該函數用於派生限制以及它所依賴的參數索引列表。 作為函數參數, deriveLimit模板函數獲取最小和最大參數值的兩個列表。

容器的最小和最大參數值

template <ParamIndex ...Indexes, typename ParamType, typename ...Args>
static ParamData deriveLimitUtil(const ParamData minParams[], const ParamData maxParams[],
                                 ParamValue<ParamType> (*function)(ParamValue<Args>...))
{
    ParamValue<ParamType> result = function(ParamValue<Args>(minParams[Indexes])..., ParamValue<Args>(maxParams[Indexes])...);
    return result.getData();
}

template <typename FuncType, FuncType function, ParamIndex ...Indexes>
static ParamData deriveLimit(const ParamData minParams[], const ParamData maxParams[])
{
    return deriveLimitUtil<Indexes...>(minParams, maxParams, function);
}

例如,為了得到參數2的上限,我調用deriveLimit如下:

deriveLimit<typeof(&DeriveTest::deriveMaxLimit2), &DeriveTest::deriveMaxLimit2, ParamIndex::PARAM_2_INT, ParamIndex::PARAM_3_FLOAT_1>(minParams, maxParams);

其中deriveMaxLimit2聲明如下:

ParamValue<int32_t> DeriveTest::deriveMaxLimit2(ParamValue<int32_t> minValue2, ParamValue<float> minValue3, ParamValue<int32_t> maxValue2, ParamValue<float> maxValue3)

問題

編譯此代碼時,編譯器返回以下錯誤:

error: mismatched argument pack lengths while expanding ‘(ParamValue<Args>)(maxParams[Indexes])’
In instantiation of ParamData deriveLimitUtil(const ParamData*, const ParamData*, ParamValue<ParamType> (*)(ParamValue<Args>...)) [with short unsigned int ...Indexes = {1u, 2u}; ParamType = int; Args = {int, float, int, float}]’:
required from ParamData deriveLimit(const ParamData*, const ParamData*) [with FuncType = ParamValue<int> (*)(ParamValue<int>, ParamValue<float>, ParamValue<int>, ParamValue<float>); FuncType function = DeriveTest::deriveMaxLimit2; short unsigned int ...Indexes = {1u, 2u}]’

如何擴展ParamValue<Args>(minParams[Indexes])...的參數包Args的一半ParamValue<Args>(minParams[Indexes])...

如何擴展ParamValue<Args>(minParams[Indexes])...的參數包Args一半ParamValue<Args>(minParams[Indexes])...

#include <tuple>
#include <utility>
#include <cstddef>

template <ParamIndex ...Indexes, typename ParamType, typename ...Args, std::size_t ...Is>
static ParamData deriveLimitUtil(const ParamData minParams[], const ParamData maxParams[],
                                 ParamValue<ParamType> (*function)(ParamValue<Args>...),
                                 std::index_sequence<Is...>)
{
    using Tuple = std::tuple<Args...>;
    ParamValue<ParamType> result = function(ParamValue<std::tuple_element_t<Is, Tuple>>(minParams[Indexes])...
                                          , ParamValue<std::tuple_element_t<Is, Tuple>>(maxParams[Indexes])...);
    return result.getData();
}

template <typename FuncType, FuncType function, ParamIndex ...Indexes>
static ParamData deriveLimit(const ParamData minParams[], const ParamData maxParams[])
{
    return deriveLimitUtil<Indexes...>(minParams, maxParams, function, std::make_index_sequence<sizeof...(Indexes)>{});
}

正如我最初想的那樣,解決方案非常簡單。 我定義了一個新的模板類ParamLimit,它表示參數的限制。 現在,我傳遞一個ParamLimit列表,而不是傳遞deriveLimit函數的兩個最小和最大參數值列表。

class ParamLimit
{
  public:
    constexpr ParamLimit(RawValue min, RawValue max) : m_min(min), m_max(max) {}

    template <typename T>
    T getLowerLimit() const { return RawValueAccessor<T>::getValue(m_min); }

    template <typename T>
    T getUpperLimit() const { return RawValueAccessor<T>::getValue(m_max); }

  private:
    RawValue m_min;
    RawValue m_max;
};

template <typename T>
class ParamLimitValue
{
  public:
    constexpr ParamLimitValue(T min, T max) : m_data(min, max) {}
    explicit ParamLimitValue(const ParamLimit& data) : m_data(data) {}

    T getLowerLimit() const { return m_data.getLowerLimit<T>(); }
    T getUpperLimit() const { return m_data.getUpperLimit<T>(); }

  private:
    ParamLimit m_data;
};

然后代碼看起來像這樣:

template <ParamIndex ...Indexes, typename ParamType, typename ...Args>
static ParamData deriveLimitUtil(const ParamLimit paramLimits[],
                                 ParamValue<ParamType> (*function)(ParamLimitValue<Args>...))
{
    ParamValue<ParamType> result = function(ParamLimitValue<Args>(paramLimits[Indexes])...);
    return result.getData();
}

template <typename FuncType, FuncType function, ParamIndex ...Indexes>
static ParamData deriveLimit(const ParamLimit paramLimits[])
{
    return deriveLimitUtil<Indexes...>(paramLimits, function);
}

和派生功能:

static ParamValue<int32_t> deriveMaxLimit2(ParamLimitValue<int32_t> param2, ParamLimitValue<float> param3);

通過這樣做,Args的大小與索引的大小匹配,並且代碼易於閱讀和維護。

暫無
暫無

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

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