C ++ Deploy only part of the parameter package

Introduction

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

In order to be able to calculate the allowable range of values ​​(minimum and maximum) for the derived parameters, I defined two new functions f_min and f_max for each derived parameter. Inside these functions, I call f with the correct combination of the values ​​of the min and max parameters to get the limit of my derived parameter.

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 save all the minimum and maximum parameter values ​​in two containers. Then I define the template function deriveLimit , which receives as arguments to the template a pointer to the function used to get the limit, and a list of parameter indices on which it depends. The deriveLimit template deriveLimit receive two lists of min and max values ​​as functional arguments.

Container for minimum and maximum 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 get the upper limit of parameter 2, I call deriveLimit as follows:

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

Where deriveMaxLimit2 is declared as follows:

 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 can I expand only half of the Args parameter package for ParamValue<Args>(minParams[Indexes])... ?

+6
source share
2 answers

How can I expand only half of the Args parameter package 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)>{}); } 
+1
source

The solution is very simple, as I originally thought. I am defining a new ParamLimit template class that represents parameter limits. Now, instead, to pass the deriveLimit function two lists 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 this:

 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 derivation function:

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

Thus, the size of Args matches the size of the indexes, and the code remains easy to read and maintain.

0
source

Source: https://habr.com/ru/post/1011714/


All Articles