简体   繁体   中英

C++ Expand only part of the parameter pack

Preface

Given I have N parameters of different types (uint, int and float) and each parameter has its own valid range of values (ie from 2.5 to 20.0). Given also that some parameters are derived from other parameters. For those parameters I use different functions (f1, f2, f3, ...).

To be able to calculate the valid range of values (minimum and maximum) of the derived parameters, I have defined for each derived parameter two new functions f_min and f_max. Inside those functions I call f with the right combination of min and max parameters values to get the limit bounds of my derived parameter.

Let's make a simple example:

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

How to solve it

First, I store all minimum and maximum parameters values into two containers. Then I define a deriveLimit template function wich gets as template arguments a pointer to the function to use to derive the limit and the list of parameter indexes that it depends on. As function arguments the deriveLimit template functions gets the two list of min and max parameter values.

容器的最小和最大参数值

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);
}

For example to derive the upper limit of parameter 2, I call deriveLimit as follow:

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

Where deriveMaxLimit2 is declared as follow:

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

Problem

When I compile this code, the compiler returns the following error:

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}]’

Question

How to I expand only half of the parameter pack Args for ParamValue<Args>(minParams[Indexes])... ?

How to I expand only half of the parameter pack Args for 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)>{});
}

The solution is much simple as I initially thought. I define a new template class ParamLimit which represents the limits of a parameter. Now, instead to pass the deriveLimit functions the two list of minimum and maximum parameter values, I pass a list of ParamLimit .

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;
};

Then the code looks like that:

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);
}

And the derivation function:

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

By doing like that, the size of Args matches with the size of Indexes and the code stays easy to read and maintainable.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM