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)
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)
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}]’
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
forParamValue<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.