假设我有 N 个不同类型的参数(uint、int 和 float),并且每个参数都有自己的有效值范围(即从 2.5 到 20.0)。还假设某些参数是从其他参数导出的。对于这些参数,我使用不同的函数(f1、f2、f3...)。
为了能够计算派生参数的有效值范围(最小值和最大值),我为每个派生参数定义了两个新函数 f_min 和 f_max。在这些函数中,我使用最小和最大参数值的正确组合来调用 f 以获得派生参数的限制范围。
我们举个简单的例子:
f(a, b) = a / b
min = f(a_min, b_max)
max = f(a_max, b_min)
首先,我将所有最小和最大参数值存储到两个容器中。然后,我定义一个
deriveLimit
模板函数,它将指向函数的指针作为模板参数,用于导出限制及其所依赖的参数索引列表。作为函数参数,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);
}
例如要导出参数2的上限,我调用
deriveLimit
如下:
deriveLimit<typeof(&DeriveTest::deriveMaxLimit2), &DeriveTest::deriveMaxLimit2, ParamIndex::PARAM_2_INT, ParamIndex::PARAM_3_FLOAT_1>(minParams, maxParams);
deriveMaxLimit2 声明如下:
ParamValue<int32_t> DeriveTest::deriveMaxLimit2(ParamValue<int32_t> minValue2, ParamValue<float> minValue3, ParamValue<int32_t> maxValue2, ParamValue<float> maxValue3)
当我编译此代码时,编译器返回以下错误:
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}]’
如何仅扩展
ParamValue<Args>(minParams[Indexes])...
的参数包 Args 的一半?
如何只扩展一半参数包
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)>{});
}
解决方案正如我最初想象的那样简单。我定义了一个新的模板类 ParamLimit ,它表示参数的限制。现在,我传递一个
deriveLimit
列表,而不是向 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;
};
那么代码如下所示:
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);
}
以及导函数:
static ParamValue<int32_t> deriveMaxLimit2(ParamLimitValue<int32_t> param2, ParamLimitValue<float> param3);
通过这样做,Args 的大小与 Indexes 的大小相匹配,并且代码保持易于阅读和维护。