Во время игры со строкой времени (переменные списки char) для компиляции мне нужно было реализовать способ проверки, содержит ли строка времени компиляции другую (меньшую) строку времени компиляции.
Это была моя первая попытка:
template<int I1, int I2, typename, typename> struct Contains;
template<int I1, int I2, char... Cs1, char... Cs2>
struct Contains<I1, I2, CharList<Cs1...>, CharList<Cs2...>>
{
using L1 = CharList<Cs1...>;
using L2 = CharList<Cs2...>;
static constexpr int sz1{L1::size};
static constexpr int sz2{L2::size};
using Type = std::conditional
<
(I1 >= sz1),
std::false_type,
std::conditional
<
(L1::template at<I1>() != L2::template at<I2>()),
typename Contains<I1 + 1, 0, L1, L2>::Type,
std::conditional
<
(I2 == sz2 - 1),
std::true_type,
typename Contains<I1 + 1, I2 + 1, L1, L2>::Type
>
>
>;
};
Я считаю, что это решение чрезвычайно легко читать и рассуждать. К сожалению, он не работает.
Компилятор всегда пытается создать экземпляр каждой отдельной ветки std::conditional, даже тех, которые не приняты. Другими словами, короткого замыкания не происходит.
Это приводит к бесконечному созданию экземпляра Contains.
Я решил свою первоначальную проблему, разделив каждый блок std::conditional в отдельном классе шаблонов, где результаты условия обрабатываются как частичные специализации.
Это работает, но, к сожалению, мне очень трудно читать/изменять.
Есть ли способ ленизировать экземпляр типа шаблона и быть близким к моему оригинальному решению?
Это пример того, как выглядит код:
using Type = std::conditional
<
(I1 >= sz1),
std::false_type,
std::conditional
<
(L1::template at<I1>() != L2::template at<I2>()),
DeferInstantiation<typename Contains<I1 + 1, 0, L1, L2>::Type>,
std::conditional
<
(I2 == sz2 - 1),
std::true_type,
DeferInstantiation<typename Contains<I1 + 1, I2 + 1, L1, L2>::Type>
>
>
>;
Возможно ли реализовать DeferInstantiation<T>?