Во время игры со строкой времени (переменные списки 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>
?