Ваш код разбит на две полностью отдельные части, серверную сторону и клиентскую сторону .
|
---------->
HTTP request
|
+--------------+ | +--------------+
| | | | |
| browser | | | web server |
| (JavaScript) | | | (PHP etc.) |
| | | | |
+--------------+ | +--------------+
|
client side | server side
|
<----------
HTML, CSS, JavaScript
|
Обе стороны общаются через HTTP-запросы и ответы. PHP выполняется на сервере и выводит код HTML и, возможно, JavaScript, который отправляется как ответ клиенту, где интерпретируется HTML, и выполняется JavaScript. Когда PHP завершит вывод ответа, сценарий закончится, и на сервере ничего не произойдет, пока не появится новый HTTP-запрос.
Пример кода выполняется следующим образом:
Шаг 1, PHP выполняет весь код между тегами . В результате получилось следующее:
Вызов file_put_contents
не привел ни к чему, он просто написал «+ foo +» в файл. Вызов привел к выводу «42», который теперь находится в том месте, где этот код использовался.
Этот итоговый код HTML / JavaScript теперь отправляется клиенту, где он получает оценку , Вызов alert
работает, а переменная foo
нигде не используется.
Весь PHP-код выполняется на сервере до того, как клиент даже начнет выполнение какого-либо JavaScript. В ответе JavaScript, с которым может взаимодействовать JavaScript, нет кода PHP.
Чтобы вызвать некоторый код PHP, клиент должен будет отправить новый HTTP-запрос на сервер. Это может произойти с использованием одного из трех возможных способов:
Вот более подробный изложение этого метода
Вы также можете использовать JavaScript, чтобы браузер открыл новую страницу с помощью window.location
или отправить форму, подражая возможностям 1 и 2.
В последнем стандарте есть ключевое слово (export
), которое поможет устранить эту проблему, но оно не реализовано ни в компилере, о котором я знаю, кроме Comeau.
Об этом можно узнать в FAQ-lite .
Нет ничего плохого в примере, который вы указали. Но я должен сказать, что считаю, что неэффективно хранить определения функций в файле cpp. Я понимаю только необходимость отделить декларацию и определение функции.
При использовании вместе с явным созданием класса, библиотека проверки возможностей Boost (BCCL) может помочь вам сгенерировать код функции шаблона в файлах cpp.
Это стандартный способ определения функций шаблона. Я думаю, что для определения шаблонов я читаю три метода. Или, возможно, 4. Каждый с плюсами и минусами.
Заметьте, я не знаю о последствиях раздутого файла obj.
Ваш пример правильный, но не очень портативный. Существует также несколько более чистый синтаксис, который можно использовать (как указано в @ namespace-sid).
Предположим, что шаблонный класс является частью некоторой библиотеки, которая должна быть разделена. Должны ли компилироваться другие версии шаблонного класса? Предполагается ли разработчик библиотеки предвидеть все возможные шаблонные применения класса?
Альтернативный подход - это небольшое изменение в отношении того, что у вас есть: добавьте третий файл, являющийся файлом реализации / создания шаблона.
foo.h file
// Standard header file guards omitted
template <typename T>
class foo
{
public:
void bar(const T& t);
};
foo.cpp file
// Always include your headers
#include "foo.h"
template <typename T>
void foo::bar(const T& t)
{
// Do something with t
}
foo-impl.cpp file
// Yes, we include the .cpp file
#include "foo.cpp"
template class foo<int>;
caveat заключается в том, что вам нужно сообщить компилятору компилировать foo-impl.cpp
вместо foo.cpp
, поскольку компиляция последнего ничего не делает.
Конечно, вы можете иметь несколько реализаций в третьем файле или иметь несколько файлов реализации для каждого типа, который вы хотели бы использовать.
Это дает гораздо большую гибкость при совместном использовании шаблона для других целей.
Эта настройка также сокращает время компиляции для повторно используемых классов, повторно не перекомпилировать один и тот же заголовочный файл в каждой единицы перевода.
foo.cpp
), из которых версии фактически скомпилированы (в foo-impl.cpp
) и деклараций (в foo.h
). Мне не нравится, что большинство шаблонов C ++ полностью определены в файлах заголовков. Это противоречит стандарту C / C ++ пар c[pp]/h
для каждого класса / пространства имен / любой группы, которую вы используете. Люди, похоже, все еще используют монолитные файлы заголовков просто потому, что эта альтернатива широко не используется или не известна.
– Cameron Tacklind
29 March 2017 в 20:06
Время обновления! Создайте встроенный (.inl или, возможно, любой другой) файл и просто скопируйте все свои определения в нем. Не забудьте добавить шаблон над каждой функцией (template <typename T, ...>
). Теперь вместо включения файла заголовка в встроенный файл вы делаете обратное. Включите встроенный файл после объявления вашего класса (#include "file.inl"
).
Я действительно не знаю, почему никто не упомянул об этом. Я не вижу немедленных недостатков.
#include "file.inl"
, препроцессор собирается вставить содержимое file.inl
прямо в заголовок. Независимо от причины, по которой вы хотели избежать реализации в заголовке, это решение не решает эту проблему.
– Cody Gray♦
25 June 2013 в 04:38
template
. Я понимаю, почему люди хотят это сделать - для достижения максимальной четкости с не-шаблонами объявлений / определений, чтобы поддерживать декларацию интерфейса, выглядящую аккуратно, и т. Д. - но это не всегда стоит хлопот. Это случай оценки компромиссов с обеих сторон и выбор наименее плохой i>. ... до namespace class
становится вещью: O [, пожалуйста, будь то i>]
– underscore_d
2 August 2016 в 20:52
Этот код хорошо сформирован. Вам нужно только обратить внимание на то, что определение шаблона видимо в момент создания экземпляра. Чтобы процитировать стандарт, § 14.7.2.4:
Определение шаблона неэкспортируемой функции, неэкспортируемый шаблон функции-члена или неэкспортированная функция-член или статический член данных шаблон шаблона должен присутствовать в каждой единицы перевода, в которой он явно создан.
blockquote>
a.cpp
(определяющие функцию a() {}
) и b.cpp
(определяющие функцию b() { a() }
), то это будет успешно связываться. Если я прав, то приведенная цитата, похоже, не будет применяться к типичному делу ... я что-то не так?
– Dan Nissenbaum
12 June 2014 в 20:46
inline
. Причина в том, что без стандартизованного C ++ ABI трудно / невозможно определить эффект, который в противном случае он имел бы.
– Konrad Rudolph
12 June 2014 в 22:41
Да, это стандартный способ выполнения специализированного экземпляра specializiation. Как вы сказали, вы не можете создать этот шаблон с другими типами.
Изменить: исправлено на основе комментария.
Это должно хорошо работать везде, где поддерживаются шаблоны. Явное создание экземпляра шаблона является частью стандарта C ++.
Для других на этой странице, интересующихся, что такое правильный синтаксис (как и я) для явной специализированности шаблонов (или, по крайней мере, в VS2008), его следующее ...
В вашем .h-файле. ..
template<typename T>
class foo
{
public:
void bar(const T &t);
};
И в вашем .cpp файле
template <class T>
void foo<T>::bar(const T &t)
{ }
// Explicit template instantiation
template class foo<int>;
Это определенно не неприятный хак, но имейте в виду, что вам нужно будет сделать это (явная спецификация шаблона) для каждого класса / типа, который вы хотите использовать с данным шаблоном. В случае МНОГИХ типов, запрашивающих создание шаблона, может быть много строк в вашем .cpp-файле. Чтобы исправить эту проблему, вы можете иметь TemplateClassInst.cpp в каждом проекте, который вы используете, чтобы у вас было больше контроля над тем, какие типы будут созданы. Очевидно, что это решение не будет идеальным (ака серебряная пуля), так как вы можете сломать ODR:).