Расширить возможности шаблонов до параметризированных синтаксических деревьев

NeoProgramming
NeoProgramming
Шаблон - это объект времени компиляции; при передаче в шаблон какого-то параметра (типа или целочисленной константы), на самом деле передается не тип и не константа, а фрагмент синтаксического дерева.
 
Поэтому я предлагаю расширить возможности шаблонов, приблизив их к возможностям синтаксических макросов:
1. разрешить передавать в качестве аргументов любые корректные фрагменты синтаксического дерева, а не только типы и целочисленые константы. В частности, параметрами шаблонов могут быть константные строки; числа с плавающей точкой; корректные идентификаторы (не значения переменных, а именно имена!); выражения; и самый общий случай - корректные блоки кода.
 
2. ввести шаблонную параметризацию не только для классов и функций, но и для других языковых конструкций - в самом общем случае для произвольных синтаксически корректных блоков кода. 
 
Рассмотрим предложение подробнее.
 
Первое, достаточно очевидное расширение - возможость передавать в качестве аргументов шаблонов константные литералы, отличные от целочисленных. Применение очевидно - значения по умолчанию, параметры алгоритмов, которые эффективнее не передавать через аргументы функций; различная метаинформация, которую можно ассоциировать с объектами.
 
template<typename T, const char *S>
struct NamedField
{
     T value;
     const char *name = S;
};
// использование
struct Foo
{
  NamedField<std::string, "User name"> username_;
  NamedField<int, "User ID"> id_;
}
 
Строковые литералы и числовые литералы с плавающей точкой ничем не хуже целочисленных; и нет никакой причины запрещать их передачу в шаблоны.
 
Второе расширение - возможность передачи в шаблоны произвольных корректных фрагментов синтаксического дерева. Фактически, это более общий случай. Передавая в шаблон число или тип, мы передаем на самом деле именно фрагмент синтаксического дерева.
 
Фрагменты синтаксического дерева просто подставляются в код, в точности как это происходит в лексических макросах препроцессора. Для обозначения фрагментов синтаксических деревьев предлагается использовать отдельное ключевое слово. Можно воспользоваться существующим словом inlineНапример, можно передать выражения:
 
template<inline Condition, inline Expr>
void Foo()
{
   while(Condition)
     Expr;
}
// использование
Foo< (x<0), { x++; } >();
 
Возможно, имеет смысл предусмотреть несколько ключевых слов для того, чтобы можно было ограничить вид фрагмента синтаксического дерева (т.е. концепты для этого). Отдельными видами могут быть
- имена (пригодные для объявления переменных и констант)
- блоки кода
- выражения
- декларативные объявления
 
Интересное следствие - возможность передавать в шаблоны типы, сформированные "на лету":
std::vector< struct { int x, y, z; } > myVec;
Это может быть полезно для различной кодогенерации.
 
Третье расширение - сами шаблоны могут быть не только классами и функциями.
Наибольший интерес представляют шаблоны - блоки кода, которые можно вставить напрямую в существующий код. Для их обозначения также предлагается использовать слово inline
 
template<unsigned int N, inline Expr>
inline FixedLoop
{
   for(unsigned int i=0; i<N; i++)
    Expr;
}

// применение
//...
FixedLoop<10, { foo(); }>;
//...
 
Как частный случай, именованные блоки кода могут быть и не шаблонными. Т.е. шаблонные блоки кода это аналог параметризированных макросов (#define) то не шаблонные - аналог макросов без параметров. Просто заготовки кода, которые непосредственно вставляются туда, где вставлены их имена.
 
Это простые примеры, показывающие синтаксис предлагаемых расширений; я не сомневаюсь, что можно придумать немало практических применений данной возможности. Например в программировании для микроконтроллеров иногда требуется иметь полный контроль над кодом - в частности, в некоторых случаях недопустимы вызовы функций, и требуется явно вставлять код в обработчики прерываний. Приходится делать на лексических макросах, что само по себе не очень красиво и безопасно.
2
рейтинг
1 комментарий
Андрей Руссков

емнип в с++20 можно будет параметризовать шаблоны constexpr значениями constexpr-сравниваемых типов. Под эту категорию попадают и указатели на функции. Например, clang 6 в режиме c++2a уже отлично кушает вот такой вот код:

#include <iostream>

template <auto func>
void foo() {
    func();
}

int main() {
    foo<+[] { std::cout << "Hello, world!" << std::endl; }>();
}

Правда, не сумеет с полиморфными лямбдами. Вкупе с template template параметрами из c++17 возможно, всё что вам нужно, уже есть?

Андрей Руссков
Другие идеи
Группа создана, чтобы собирать предложения к стандарту C++, организовывать их внутренние обсуждения, помогать готовить их для отправки в комитет и защищать на общих собраниях в рабочей группе по С++ Международной организации по стандартизации (ISO).
Все предложения