This is a patch to the GCC 7.1 source which adds a "static_print" statement to C++.
The static_print statement can be used wherever static_assert can be used, and its effect is to print a formatted message at compile time.
static_print can receive any no. of arguments, each argument being either a string literal (which is printed out), or any "template-argument" expression (anything that could be a template argument — types, constant expressions, template names, etc..), which is resolved at compile time and pretty-printed.
Unlike static_assert, static_print also behaves correctly with if constexpr! (nothing will be printed if the condition does not apply).
Example:
template<typename T, int s>
struct test
{
static_print("The template ", ::test, " has been instantiated as ", test, ". By the way, s + 1 is ", s + 1);
};
int main() {
test<int, 3> y;
return 0;
}
Compiling the above program prints out (at compile time):
The template test has been instantiated as test<int, 3>. By the way, s + 1 is 4
Здравствуйте, Skorodum, Вы писали:
S>Здравствуйте, kov_serg, Вы писали:
_>>А можно как-то тип перменной вывести, что бы далеко не лазить? S>Так он же это и делает S>
S>The template test has been instantiated as test<int, 3>. By the way, s + 1 is 4
А он пишет в какой строке исходного файла он это вывел?
terra/incognito/some_place.cpp:100500:12: static_print: The template test has been instantiated as test<int, 3>. By the way, s + 1 is 4
S>static_print can receive any no. of arguments, each argument being either a string literal (which is printed out), or any "template-argument" expression (anything that could be a template argument - types, constant expressions, template names, etc..), which is resolved at compile time and pretty-printed.
S>
S>The template test has been instantiated as test<int, 3>. By the way, s + 1 is 4
Следующий шаг — перенаправить вывод в новый файл и подсунуть его компилятору на компиляцию...
Т.е. можно получить кодогенерацию в момент компиляции с помощью компилятора:
template<typename T, int s>
struct test_generator
{
static_print("struct test_", s, " { char m_name[", s + 1, "]; };");
};
Сдаётся мне, что это прямая альтернатива метаклассам
Здравствуйте, B0FEE664, Вы писали:
BFE>Следующий шаг — перенаправить вывод в новый файл и подсунуть его компилятору на компиляцию... BFE>Т.е. можно получить кодогенерацию в момент компиляции с помощью компилятора:
BFE>
Зачем так извращаться, если в D уже есть более простой и отлично работающий механизм — функция mixin. На мой взгляд её давным давно пора засунуть в C++. Хотя нет, в начале всё же надо ещё разрешить в C++ полноценную работу со строками во время компиляции.
Здравствуйте, alex_public, Вы писали:
_>Зачем так извращаться, если в D уже есть более простой и отлично работающий механизм — функция mixin. На мой взгляд её давным давно пора засунуть в C++. Хотя нет, в начале всё же надо ещё разрешить в C++ полноценную работу со строками во время компиляции.
Не надо такого.
Лучше дать нормальный API и работать через него.
Здравствуйте, _NN_, Вы писали:
_>>Зачем так извращаться, если в D уже есть более простой и отлично работающий механизм — функция mixin. На мой взгляд её давным давно пора засунуть в C++. Хотя нет, в начале всё же надо ещё разрешить в C++ полноценную работу со строками во время компиляции. _NN>Не надо такого. _NN>Лучше дать нормальный API и работать через него.
Так mixin — это и есть нормальный API для генерации кода средствами метапрограммирования.
Здравствуйте, jazzer, Вы писали:
_>>Так mixin — это и есть нормальный API для генерации кода средствами метапрограммирования. J>костыли это, а не API
Ну тогда приведи пример, как выглядели бы не костыли. )
Кстати, данных костылей вполне хватает для реализации например такого https://github.com/rejectedsoftware/diet-ng/ DSL (естественно речь про встраиваемый прямо в язык, а не внешний препроцессор).
Здравствуйте, _NN_, Вы писали:
_>>Так mixin — это и есть нормальный API для генерации кода средствами метапрограммирования. _NN>Мы кстати про какие миксины говорим? _NN>String mixin точно не нужен.
Да, речь именно про них. А что ты считаешь лучшей альтернативой такому решению? Естественно оставаясь в рамках компилятора C++ (без всяких внешних препроцессоров)...
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, jazzer, Вы писали:
_>>>Так mixin — это и есть нормальный API для генерации кода средствами метапрограммирования. J>>костыли это, а не API
_>Ну тогда приведи пример, как выглядели бы не костыли. )
Как в .NET, например. Когда есть, собственно, API (т.е. объекты, методы и прочая), а не просто текстовые макросы:
CodeMemberMethod clearEntityMethod = new CodeMemberMethod();
genClass.Members.Add(clearEntityMethod);
clearEntityMethod.Name = "ClearEntity";
clearEntityMethod.ReturnType = new CodeTypeReference(typeof(void));
clearEntityMethod.Parameters.Add(new CodeParameterDeclarationExpression(entityType, "entity"));
_>Кстати, данных костылей вполне хватает для реализации например такого https://github.com/rejectedsoftware/diet-ng/ DSL (естественно речь про встраиваемый прямо в язык, а не внешний препроцессор).
Не сомневаюсь. Мне сишного препроцессора тоже до сих пор хватало (при помощи Boost.Preprocessor, конечно), но тем не менее это костыли.
Здравствуйте, jazzer, Вы писали:
_>>Ну тогда приведи пример, как выглядели бы не костыли. ) J>Как в .NET, например. Когда есть, собственно, API (т.е. объекты, методы и прочая), а не просто текстовые макросы: J>
J>CodeMemberMethod clearEntityMethod = new CodeMemberMethod();
J>genClass.Members.Add(clearEntityMethod);
J>clearEntityMethod.Name = "ClearEntity";
J>clearEntityMethod.ReturnType = new CodeTypeReference(typeof(void));
J>clearEntityMethod.Parameters.Add(new CodeParameterDeclarationExpression(entityType, "entity"));
J>
Ну так это в рантайме — совсем не то (и кстати реализуется в C++ без каких-либо правок языка/компилятора, только мало кому нужно). Или ты имел ввиду, что сделать набор таких типов и функций, доступных для выполнения во время-компиляции (типа static_assert)? Ну и даже если сделать так (получится как бы ещё один встроенный язык, который надо будет как-то отделять от основного), то в чём ты видишь преимущество такого подхода для метапрограммирования времени компиляции?
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, _NN_, Вы писали:
_>>>Так mixin — это и есть нормальный API для генерации кода средствами метапрограммирования. _NN>>Мы кстати про какие миксины говорим? _NN>>String mixin точно не нужен.
_>Да, речь именно про них. А что ты считаешь лучшей альтернативой такому решению? Естественно оставаясь в рамках компилятора C++ (без всяких внешних препроцессоров)...
Что значит в рамках компилятора ? Любая фича выходит за рамки того, что есть сейчас.
Лучшей альтернативой было бы нормальное квази-цитирование.
Т.е. построение дерева выражения за тебя.
Вместо такого:
string makeStruct(string name)
{
return"struct " + name + "{" + "}" + ";"; // Что если в name передать плохое имя ?;)
}
Здравствуйте, _NN_, Вы писали:
_>>Да, речь именно про них. А что ты считаешь лучшей альтернативой такому решению? Естественно оставаясь в рамках компилятора C++ (без всяких внешних препроцессоров)... _NN>Что значит в рамках компилятора ? Любая фича выходит за рамки того, что есть сейчас.
Имеется в виду, что в рамках изменения самого компилятора, а не навешиванием внешних инструментов (типа Qt MOC).
_NN>Лучшей альтернативой было бы нормальное квази-цитирование. _NN>Т.е. построение дерева выражения за тебя. _NN>Вместо такого: _NN>
_NN>string makeStruct(string name)
_NN>{
_NN> return"struct " + name + "{" + "}" + ";"; // Что если в name передать плохое имя ?;)
_NN>}
_NN>
В D в этом случае будет ошибка компиляции со вполне вменяемым сообщением. Единственный минус тут в том, что указывать ошибка будет на строчку с mixin, а не на функцию makeStruct.
_NN>Был бы код типа: _NN>
_NN>Где этот код вызывается на этапе компиляции и выдаёт вменяемые ошибки в случае чего.
Это похоже ближе к макросам Rust или Nim. И оно конечно приятнее, но требует по сути введения нового языка в компилятор C++. Я в принципе не против, но сомневаюсь что на такое пойдут. А вот добавить одну скромную и несложную функцию типа mixin по идее могли бы...
_NN>Что-то в стиле варианта C++ Metaclasses
Метаклассы мне понравились. Особенно то, что все текущие стандартные и нестандартные (типа Qt или сериализаций из Boost) сущности в них укладываются. Но это всё равно заметно более узкий подход, чем возможность генерации произвольного кода.
_>В D в этом случае будет ошибка компиляции со вполне вменяемым сообщением. Единственный минус тут в том, что указывать ошибка будет на строчку с mixin, а не на функцию makeStruct.
Потом появятся библиотеки для объектного создания этого дела и будет:
Я даже уверен, что кто-то такое сделал.
Только типизация пропадает сразу после выхода из этой функции да и писать такой код вместо цитирования неочень приятно.
_>Это похоже ближе к макросам Rust или Nim. И оно конечно приятнее, но требует по сути введения нового языка в компилятор C++. Я в принципе не против, но сомневаюсь что на такое пойдут. А вот добавить одну скромную и несложную функцию типа mixin по идее могли бы...
Всё остальное это полумеры.
Можно конечно решить где предел, как шаблоны C++, шаблоны D, а можно сразу сделать как надо и получить все плюшки.
Кстати в Rust насколько я понял там нет отладки, максимум это: cargo-expand.
Я говорю про такие, которые можно отлаживать, как в Nemerle, например.
Здравствуйте, _NN_, Вы писали:
_>>В D в этом случае будет ошибка компиляции со вполне вменяемым сообщением. Единственный минус тут в том, что указывать ошибка будет на строчку с mixin, а не на функцию makeStruct. _NN>Потом появятся библиотеки для объектного создания этого дела и будет: _NN>
_NN>Я даже уверен, что кто-то такое сделал. _NN>Только типизация пропадает сразу после выхода из этой функции да и писать такой код вместо цитирования неочень приятно.
Возможно. Но для людей имеющих в данный момент метапрограммирование только на шаблонах C++ и такое может показаться замечательным. )
_>>Это похоже ближе к макросам Rust или Nim. И оно конечно приятнее, но требует по сути введения нового языка в компилятор C++. Я в принципе не против, но сомневаюсь что на такое пойдут. А вот добавить одну скромную и несложную функцию типа mixin по идее могли бы... _NN>Всё остальное это полумеры. _NN>Можно конечно решить где предел, как шаблоны C++, шаблоны D, а можно сразу сделать как надо и получить все плюшки.
Ну я уже писал раньше, что как раз являюсь сторонниками "максимального" развития метапрограммирования в C++. Однако я при этом ещё и реалист. Так что предпочту получить хоть что-то (например аналог mixin из D), чем не получить ничего, предаваясь мечтаниям о полноценных синтаксических макросах.
_NN>Кстати в Rust насколько я понял там нет отладки, максимум это: cargo-expand. _NN>Я говорю про такие, которые можно отлаживать, как в Nemerle, например.
На мой взгляд для отладки подобных вещей гораздо полезнее наличие отладочной печати. Кстати, для решения типа mixin в этой роли хватило бы как раз static_print из данной темки. А вот для полноценных макросов нужно уже что-то типа print_ast, что впрочем тоже не особая проблема.
Здравствуйте, alex_public, Вы писали:
_>Ну я уже писал раньше, что как раз являюсь сторонниками "максимального" развития метапрограммирования в C++. Однако я при этом ещё и реалист. Так что предпочту получить хоть что-то (например аналог mixin из D), чем не получить ничего, предаваясь мечтаниям о полноценных синтаксических макросах.
Это пройденный этап.
"Александреску" появится гораздо раньше чем кажется.
Поэтому лучше сразу по максимуму.
Тогда и код проще будет и полезности больше.
_>На мой взгляд для отладки подобных вещей гораздо полезнее наличие отладочной печати. Кстати, для решения типа mixin в этой роли хватило бы как раз static_print из данной темки. А вот для полноценных макросов нужно уже что-то типа print_ast, что впрочем тоже не особая проблема.
У меня есть опыт в отлаживании макросов и могу сказать, что это гораздо лучше чем полумеры вида print_ast