Это связано с требованием отдельной компиляции и потому, что шаблоны являются полиморфизмом типа создания экземпляров.
Давайте немного приблизимся к конкретному для объяснения. Скажем, у меня есть следующие файлы:
class MyClass<T>
class MyClass<T>
MyClass<int>
. Отдельное средство компиляции. Я должен скомпилировать foo.cpp независимо от bar.cpp. Компилятор полностью выполняет всю сложную работу по анализу, оптимизации и генерации кода на каждом модуле компиляции; нам не нужно анализировать целую программу. Только компоновщик должен обрабатывать всю программу одновременно, и задача компоновщика значительно упрощается.
bar.cpp даже не нужно существовать при компиляции foo.cpp, но я все равно должен быть в состоянии связать foo.o Я уже имел вместе с bar.o Я только что выпустил, не перекомпилируя foo.cpp. foo.cpp может даже быть скомпилирован в динамическую библиотеку, распределенную где-то в другом месте без foo.cpp, и связан с кодом, который они пишут спустя годы после того, как я написал foo.cpp.
«Полиморфизм в стиле объектов» означает, что template MyClass<T>
не является общим классом, который может быть скомпилирован в код, который может работать для любого значения T
. Это добавит накладные расходы, такие как бокс, необходимо передать указатели на функции для распределителей и конструкторов и т. Д. Намерение шаблонов C ++ состоит в том, чтобы избежать необходимости писать почти идентичные class MyClass_int
, class MyClass_float
и т. Д., Но все же быть в состоянии закончить с компилируемым кодом, который в основном выглядит так, как если бы мы имели каждую версию отдельно. Таким образом, шаблон является буквально шаблоном; шаблон класса не класс, это рецепт создания нового класса для каждого T
, с которым мы сталкиваемся. Шаблон не может быть скомпилирован в код, только результат создания экземпляра шаблона может быть скомпилирован.
Итак, когда foo.cpp скомпилирован, компилятор не может видеть bar.cpp, чтобы знать, что MyClass<int>
необходимо. Он может видеть шаблон MyClass<T>
, но он не может испускать код для этого (это шаблон, а не класс). И когда компилируется bar.cpp, компилятор может видеть, что ему нужно создать MyClass<int>
, но он не может видеть шаблон MyClass<T>
(только его интерфейс в foo.h), поэтому он не может его создать.
Если foo.cpp сам использует MyClass<int>
, тогда код для него будет сгенерирован при компиляции foo.cpp, поэтому, когда bar.o связан с foo.o, они могут быть подключены и будут работать. Мы можем использовать этот факт, чтобы позволить конечный набор экземпляров шаблонов быть реализован в .cpp-файле, написав один шаблон. Но bar.cpp не может использовать шаблон в качестве шаблона и создавать его на всех типах, которые ему нравятся; он может использовать только ранее существовавшие версии шаблона, которые автор foo.cpp думал предоставить.
Вы можете подумать, что при компиляции шаблона компилятор должен «сгенерировать все версии», с теми, которые никогда не используются, отфильтровываются во время связывания. Помимо огромных накладных расходов и экстремальных трудностей, с которыми сталкивался такой подход, поскольку «модификаторы типа», такие как указатели и массивы, позволяют даже встроенным типам создавать бесконечное количество типов, что происходит, когда я расширяю свою программу добавив:
class BazPrivate
и использует MyClass<BazPrivate>
Невозможно, чтобы это могло работать, если мы либо
MyClass<T>
MyClass<T>
, чтобы компилятор мог генерировать MyClass<BazPrivate>
во время компиляции baz.cpp. Никто не любит (1), потому что системы компиляции целых программ принимают forever для компиляции и потому что это делает невозможным распространение компилированных библиотек без исходного кода. Итак, у нас есть (2).
Если вы используете fpdf, чтобы иметь возможность использовать разрывы строк, вам нужно будет использовать многострочную текстовую ячейку , как описано здесь .
Если вы используете это, тогда разрывы строк в вашем тексте должны интерпретироваться и преобразовываться правильно.
Просто быстрый пример:
$pdf->Multicell(0,2,"This is a multi-line text string\nNew line\nNew line");
Здесь 2 - высота многострочного текстового поля. Я не знаю, в каких единицах это измеряется, и можно ли просто установить его на 0 и игнорировать. Возможно, попробуйте с большим числом, если сначала это не сработает.
Ваш код читает
$pdf->InsertText('Line one\n\nLine two');
Я не знаю о библиотеке PDF, которую вы используется, но обычно, если вы хотите, чтобы \ n интерпретировался как разрыв строки, вы должны использовать двойные кавычки в PHP, например
$pdf->InsertText("Line one\n\nLine two");
Я бы скомпилировал его с помощью leininge n, затем добавить файл jar в мой проект java в качестве dep. Вот отличный видео об использовании leiningen. тогда вы называете его прямо с java. У Leiningen есть опция uberjar, которая колеблется в клоюре и всех ваших клоюрных зависимостях, так что вам нужно беспокоиться только об одном файле. Мне нравится это, потому что его меньше работы.
Более понятным подходом к Java было бы добавить задачу ant, чтобы построить ее вместе с проектом Java, его просто немного больше работы
для функций, которые должны вернуть соответствующие массивы Java вызвать к массиву
на них
вопреки многим из верхних «Вызов clojure из java» попаданий вы не должны вызывать clojure среды выполнения RT.
PS: моя любимая строка тэга «Я хотел бы использовать библиотеку java под названием clojure» Я спросил Рича, что это круто;)
-121--2711756-Если у вас есть запасная коробка, я бы предложил Нант и [CruiseControl.net]. Вам не обязательно использовать его для непрерывной интеграции, вы можете настроить ваши сборки на выполнение [только при принудительном]. Оба источника являются открытыми, имеют встроенную поддержку SVN и довольно просты в использовании. Я использовал Nant & CrureControl.Net для каждой из перечисленных вами вещей, кроме задачи doxygen. Даже без запасной коробки я бы предложил использовать Nant для автоматизации вашего выхода из того, что выглядит как длинная серия ручных задач.
-121--4690888-Указывается, что
2 - высота многострочного текстового поля
Нет. 2 - расстояние между строками текста.
Я не думаю, что существует реальный способ вычисления высоты фактического результирующего текстового поля, если вы не используете GetY ()
, а затем вычитаете исходное значение Y, используемое в операторе SetXY ()
для размещения Мультиклетки на первом месте.