Pull to refresh

Comments 12

UFO just landed and posted this here

Можно вопрос от неспециалиста в C++?

А почему нельзя просто заинклюдить библиотеку и вызывать оттуда нужные фии?

Чем лучше писать какие-то сущности в комментариях, которые потом развернутся в код?

Это особенность работы с шаблонами в C++. Пусть есть объявление такой шаблонной функции:

template<typename EnumType>
EnumType FromInt(int value);

Тогда, подставляя вместо EnumType разные типы данных (например FromInt<Color>(100500), мы получим разные функции - по одной функции на каждый EnumType. Шаблонная функция (и вообще шаблонный код) это просто заготовка реального кода.

Вывод компилятора с двумя функциями

Таким образом, кодогенератор создает определения подобных частных функций рядом с исходниками, и затем компилятор связывает вызов шаблонной функции с конкретным определением функции.

В какой-то совсем внешней библиотеке эти определения находиться не смогут, потому что внешние библиотеки не имеют никакого понятия про типы данных в конкретной программе. Пусть внутри программы есть тип enum Foo, тогда программа должна сама заботиться о наличии определения функции FromInt<Foo>.

В какой-то совсем внешней библиотеке эти определения находиться не смогут

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

Я правильно понимаю, что у нас есть некая шаблонная функция?

Ну для примера пусть будет minimum:

template <typename T> T minimum (const T &a, const T &b) {
  return a < b ? a : b;
}

Есть внешний файл, где она объявлена, допустим utils.cpp

Если понадобилось вызвать эту фю для какого-либо произвольного типа где-либо в другом файле, можно же сделать так:

#include "utils.cpp"
typedef unsigned int MYTYPE;
MYTYPE a = 5, b = 7;
cout << minimum( a, b );

Или я задачу не верно понял?

Кодогенератор это программа, которая на основе исходного кода или какого-нибудь файла настроек генерирует вспомогательный код, который потом компилируется вместе с исходным кодом. Это нужно, чтобы не писать boilerplate-код (копипаст)

Или на примере того-же мока - напиши его один раз, вынеси в отдельный файл - и где надо - заинклюдь чтобы не было boilerpate-а.

Начните с основ. Почитайте про то что такое препроцесстрование, компиляция и линковка.

После - чем объявление функции отличается от определения. Потом про шаблонные функции. Вы найдете ответы на все ваши вопросы. Пока лишь создаётся впечатление что вы очень плохо понимаете то, о чём спрашиваете.

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

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

Шаблоны это слишком мощный инструмент в этом плане. Ты можешь написать шаблон который будет использовать какие-то специфичные методы класса и после компиляции увидеть конкретные ошибки.

Условно написать "template<class T> bool min(T a, T b) { return a<b; }"

И любой класс который реализует оператор сравнения спокойно компилируется. Единственное, как по мне, ограничение что нельзя автоматически определять типы результатов функций, типа "template<class T, class U> T do (U a) { return a.some(); }"

В таких случая компилятор не даст нам нормально скомпилировать не код. Это решается метаобъектами через те же шаблоны. Грубо говоря у нас будет "meta<T> do(U a);"

UPD meta<T> будет иметь оператор приведения типа, который автоматически скастует его в то что нужно.

Такой код будет компилироваться и оптимизироваться компилятором. Но это ограничивает наш проект статической сборкой)

Большинство крестовых программистов, с моей точки зрения, боятся шаблонов, потому и пишут "подобный" код, не понимая что сломав себе мозг однажды... ты получишь удобный инструмент.

UPD так же есть вспомогательные шаблонные методы, которые можно найти на сайтике цппреференс. Благодаря хитрым конструкциям можно писать совершенно безумные вещи. Типа написать реализацию свойств почти как в C#. У меня это выглядело как "property<int> rate = { SET( I2C::Send(...) ), GET( return I2C::Get(...)) };"

Не совсем понял, по вашему развернутся в код кем и когда? И что значит заинклюдить библиотеку?

Инклюдятся заголовочные файлы библиотеки (если речь не о новомодных модулях из последнего стандарта). "Вызов функций" происходит во время работы приложения, а нам же надо во время написания кода, до компиляции.

 почему нельзя просто заинклюдить библиотеку и вызывать оттуда нужные фии?

Потому что что-то нельзя сделать в рамках языка без дополнительного бойлерплейта

Я наверное ретроград какой-то, но кодогенераторы (например, Qt moc) и всякие искуственные слоты и сигналы вызывают у меня отторжение.

Можно считать, что сам C++ это тоже кодогенератор для ассемблера.

Кодогенераторы схожи с надмножествами языков программирования. Тут, обратная совместимость (без учета генерации) сохраняется за счет комментариев, ну и это в целом аналогично кодогенераторам на Qt (как написали выше).

На данный момент возможности реализовать это в макросах нет?

P. S. Rust serde передает привет

Sign up to leave a comment.

Articles