Fold expression. Подробности.



В сущности, fold expression - сворачивание всего пака шаблонных параметров с помощью комбинации синтаксиса variadic templates и бинарных операторов. Есть всего 4 формата, в которых можно использовать эту фичу.



1️⃣ ( pack op ...) - унарный правый фолд

2️⃣ ( ...  op pack) - унарный левый фолд

3️⃣ (pack op ... op init ) - бинарный правый фолд

4️⃣ (init op ... op pack) - бинарный левый фолд



где pack - выражение, содержащее нераспакованный набор шаблонных параметров. op - бинарный оператор. В последних двух случаях он должен быть одинаковым справа и слева от точек. В число бинарных операторов входит почти все, что вы могли бы себе представить: +  -    /   %  ^   &   |   =   <   >   <<   >>   +=  -=   =   /= %=   ^=   &=   |=   <<=   >>=   ==   !=   <=   >=   &&   ||   ,   .   ->. init - выражение, которое никак не относится к шаблонным параметрам и является базой вычислений. Это как в std::accumulate вы можете выставить начальное значение для аггрегации. Вот это тоже самое.



Опустил некоторые не очень важные детали. Дай бог вам попользоваться этой фичей, в корнер кейсах разберетесь сами.



Очень важное уточнение по поводу левых и правых фолдов.



👉🏿 Унарный  правый фолд (E op ...) раскрывается в  (E1 op (... op (En-1 op En)))

👉🏿 Унарный левый фолд (... op E) раскрывается в  (((E1 op E2) op ...) op En)

👉🏿 Бинарный правый фолд (E op ... op init) раскрывается в  (E1 op (... op (En−1 op (EN op init))))

👉🏿 Бинарный левый фолд(init op ... op E) раскрывается в  ((((init op E1) op E2) op ...) op En)



И тут очень сильно решает коммутативность операции. То есть неависимость от порядка аргументов. Если оператор обладает этим свойством, как например сложение или умножение, то можете не париться о порядке. Пишите, как удобно. А вот если от порядка операндов зависит итоговый результат операции(тот же бинарный сдвиг), то подумайте, какой именно фолд подойдет для решения вашей задачи.



А помните, я вчера упоминал функцию Sum, которую нельзя расшаблонивать с нулевым количеством аргументов(там в комментах @PyXiion придумал как, но я сейчас имею ввиду нативный формат без оберток)? Вот сейчас и коснемся этого вопроса.



Функция без аргументов - всегда был особым случаем при использовании вариадик шаблонов. И для fold expression она также является таковым. Тут следующие правила:



💥 У оператора Логическое И (&&) значение для пустого набора параметров - true.

💥 У оператора Логическое ИЛИ (||) значение для пустого набора параметров - false.

💥 У оператора "запятая" (,) значение для пустого набора параметров - void().

☠️ Для всех остальных операторов конкретизация шаблона с пустым набором параметров запрещена.



Почему так? А непонятно, какой результат у сложения ничего с ничем. Или непонятно, что будет если у ничего сдвинуть несуществующие биты вправо на никакое количество позиций. И так далее. И соответственно, тут надо либо использовать инициализатор, либо обвязки писать. Но вот для трех операторов нашелся логичный результат, поэтому они вот такие особенные.



В следующий раз в подробностях разберем, как нормально принтоваться с помощью fold expression. Это довольно популярное и нужное применение. Может и не в продакшен коде. Но при экспериментах или при отладке поможет сильно сократить время и ошибки.



Постарался кое-где использовать ваши синонимы, отпишите, как звучит.



Explore internals of things. Stay cool.



#cpp17 #template