简体   繁体   English

C ++仅扩展参数包的一部分

[英]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). 鉴于我有不同类型的N个参数(uint,int和float),并且每个参数都有自己的有效值范围(即从2.5到20.0)。 Given also that some parameters are derived from other parameters. 还给出了一些参数来自其他参数。 For those parameters I use different functions (f1, f2, f3, ...). 对于那些参数,我使用不同的函数(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. 为了能够计算派生参数的有效值范围(最小值和最大值),我为每个派生参数定义了两个新函数f_min和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. 在这些函数中,我使用min和max参数值的正确组合调用f来获取派生参数的限制边界。

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. 然后我定义一个deriveLimit模板函数,它获取模板参数作为指向函数的指针,该函数用于派生限制以及它所依赖的参数索引列表。 As function arguments the deriveLimit template functions gets the two list of min and max parameter values. 作为函数参数, 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);
}

For example to derive the upper limit of parameter 2, I call deriveLimit as follow: 例如,为了得到参数2的上限,我调用deriveLimit如下:

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

Where deriveMaxLimit2 is declared as follow: 其中deriveMaxLimit2声明如下:

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])... ? 如何扩展ParamValue<Args>(minParams[Indexes])...的参数包Args的一半ParamValue<Args>(minParams[Indexes])...

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

The solution is much simple as I initially thought. 正如我最初想的那样,解决方案非常简单。 I define a new template class ParamLimit which represents the limits of a parameter. 我定义了一个新的模板类ParamLimit,它表示参数的限制。 Now, instead to pass the deriveLimit functions the two list of minimum and maximum parameter values, I pass a list of 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;
};

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. 通过这样做,Args的大小与索引的大小匹配,并且代码易于阅读和维护。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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