Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 (i.e. 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.

Container for the 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 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])...?

like image 321
lucaboni Avatar asked Oct 26 '16 10:10

lucaboni


People also ask

How do you expand a parameter pack?

Parameter packs can only be expanded in a strictly-defined list of contexts, and operator , is not one of them. In other words, it's not possible to use pack expansion to generate an expression consisting of a series of subexpressions delimited by operator , .

What is a parameter pack?

[edit] A template parameter pack is a template parameter that accepts zero or more template arguments (non-types, types, or templates). A function parameter pack is a function parameter that accepts zero or more function arguments. A template with at least one parameter pack is called a variadic template.


1 Answers

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)>{});
}
like image 102
Piotr Skotnicki Avatar answered Sep 22 '22 19:09

Piotr Skotnicki