Как реализовать параметризованные шаблоны классов с минимальным шаблоном

В моем программном обеспечении, где часто используется метапрограммирование шаблонов, классы шаблонов часто принимают шаблоны классов в качестве аргументов, которые определяют определенные аспекты их поведения. В качестве очень простого примера, предположим, у нас есть класс 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 корневому классу, и он распространяется на все остальное.

Эти примеры являются искусственными, но они должны объяснить проблему. Я не хочу, чтобы конфигурация содержала больше шаблонов, чем необходимо (в частности, константы с плавающей точкой не могут быть определены, как указано выше …).

Наконец, необходимо использовать метапрограммирование шаблона (как по соображениям производительности, так и в соответствии с существующим кодом).

1

Решение

Я понимаю, что ваш пример несколько надуманный, но я не вижу причин для параметров шаблона и вложенности. Поэтому я предлагаю удалить их и выполнить всю параметризацию типов параметров на уровне формулы. Это создает «аккуратное» и менее вложенное решение, но, возможно, не то, которое вам пригодится. Также обратите внимание, что я переместил параметры шаблона с плавающей запятой в класс политики.

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>>;
0

Другие решения

Других решений пока нет …