在我的软件中,模板元编程被大量使用,模板类通常将类模板作为参数来定义其行为的某些方面。作为一个非常简单的例子,假设我们有一个类FormulaUser
,它需要使用公式来计算两个其他数字的数字,并且必须将特定公式指定为模板参数。此外,关于它操作的数据类型(浮点数或双精度数),公式需要打开。例如:
template <template<typename> class Formula, typename FpType>
struct FormulaUser {
using TheFormula = Formula<FpType>;
void some_function ()
{
FpType x = 1;
FpType y = 2;
FpType result = TheFormula::calculate(x, y);
}
};
template <typename FpType>
struct AddFormula {
static FpType calculate (FpType x, FpType y) { return x + y; }
};
// composition:
using TheFormulaUser = FormulaUser<AddFormula, float>;
这没关系,但是当公式本身需要在传递给FormulaUser
之前定义参数时,这不是很多。例如,LinearFormula
(让我们忽略浮点类型不能作为模板参数的事实):
template <float A, float B, float C>
struct LinearFormula {
template <typename FpType>
struct Formula {
static FpType calculate (FpType x, FpType y) { return A + B*x + C*y; }
};
};
// composition:
using TheFormulaUser = FormulaUser<LinearFormula<1.0, 2.0, 3.0>::template Formula, float>;
我不喜欢这段代码:
::template Formula part
)。LinearFormula
的肉缩进了两次。有没有办法让它更好?
更新
我希望将公式参数分为两个级别(公式常量和FpType)的原因是第一组中的那些是用户配置的一部分,而第二组中的那些是由正在制作的类提供的使用公式。好吧,FpType也最终作为用户配置,但对于所有公式应该是相同的。这个更复杂的构图证明了这一点......
using MyProgram = Program<
float, // FpType
AddFormula, // Formula for something
LinearFormula<2.0, 5.3, 5.3>, // Formula for something else
QuadraticFormula<.....>, // For something else...
ExponentialAveraging< // AveragingType
0.6 // SmoothingFactor
>
>;
因此,您将FpType提供给根类,并将其传播到其他所有内容。
这些例子是人为的,但它们应该解释这个问题。我不希望配置有任何超出必要的样板(特别是浮动常量不能真正指定如上......)。
最后,要求使用模板元编程(出于性能原因以及与现有代码的一致性)。
答案 0 :(得分:0)
我意识到你的例子有点人为,但我没有理由看到模板模板参数和嵌套。所以我的建议是删除它们并在公式级别执行所有参数类型参数化。这会创建一个“整洁”和较少嵌套的解决方案,但可能不是对您有用的解决方案。另请注意,我将浮点模板参数移动到策略类中。
template <class Formula>
struct FormulaUser
{
using param_type = typename Formula::param_type;
param_type some_function()
{
param_type x = 1;
param_type y = 2;
return Formula::calculate(x, y);
}
};
template <typename FpType>
struct AddFormula
{
using param_type = FpType;
static FpType calculate(FpType x, FpType y) { return x + y; }
};
using TheFormulaUser = FormulaUser<AddFormula<float>>;
struct SomeCoefficients
{
static float A()
{
return 1.0;
}
static float B()
{
return 2.0;
}
static float C()
{
return 3.0;
}
};
template <typename FPType, typename LinearPolicy>
struct LinearFormula
{
using param_type = FPType;
static FPType calculate(FPType x, FPType y)
{
return LinearPolicy::A() + LinearPolicy::B() * x + LinearPolicy::C() * y;
}
};
// composition:
using TheFormulaUser2 = FormulaUser<LinearFormula<float, SomeCoefficients>>;