Использование DateTime:
$given = new DateTime("2014-12-12 14:18:00");
echo $given->format("Y-m-d H:i:s e") . "\n"; // 2014-12-12 14:18:00 Asia/Bangkok
$given->setTimezone(new DateTimeZone("UTC"));
echo $given->format("Y-m-d H:i:s e") . "\n"; // 2014-12-12 07:18:00 UTC
не необходимо поместить реализацию в заголовочный файл, видеть альтернативное решение в конце этого ответа.
Так или иначе, причина, которую приводит к сбою Ваш код, состоит в том, что при инстанцировании шаблона компилятор создает новый класс с данным аргументом шаблона. Например:
template<typename T>
struct Foo
{
T bar;
void doSomething(T param) {/* do stuff using T */}
};
// somewhere in a .cpp
Foo<int> f;
При чтении этой строки, компилятор создаст новый класс (давайте назовем его FooInt
), который эквивалентен следующему:
struct FooInt
{
int bar;
void doSomething(int param) {/* do stuff using int */}
}
, Следовательно, компилятор должен иметь доступ к реализации методов, для инстанцирования их с аргументом шаблона (в этом случае int
). Если бы эти реализации не были в заголовке, то они не были бы доступны, и поэтому компилятор не смог бы инстанцировать шаблона.
общее решение А этого состоит в том, чтобы записать объявление шаблона в заголовочном файле, затем реализовать класс в файле реализации (например, .tpp) и включать этот файл реализации в конце заголовка.
// Foo.h
template <typename T>
struct Foo
{
void doSomething(T param);
};
#include "Foo.tpp"
// Foo.tpp
template <typename T>
void Foo<T>::doSomething(T param)
{
//implementation
}
Таким образом, реализация все еще разделяется от объявления, но доступна для компилятора.
Другое решение состоит в том, чтобы сохранить реализацию разделенной и явно инстанцировать всех шаблонных экземпляров, в которых Вы будете нуждаться:
// Foo.h
// no implementation
template <typename T> struct Foo { ... };
//----------------------------------------
// Foo.cpp
// implementation of Foo's methods
// explicit instantiations
template class Foo<int>;
template class Foo<float>;
// You will only be able to use Foo with int or float
, Если мое объяснение не является достаточно четким, можно взглянуть на C++ супер-FAQ на этом предмете .
Хотя в стандарте C ++ такого требования нет, некоторые компиляторы требуют, чтобы все шаблоны функций и классов были доступны в каждой используемой им единице перевода. По сути, для этих компиляторов тела шаблонных функций должны быть доступны в заголовочном файле. Повторим: это означает, что эти компиляторы не позволят им быть определенными в файлах без заголовка, таких как файлы .cpp
. Существует ключевое слово export , которое должно решить эту проблему, но это далеко не портативно.
Шаблоны должны быть созданы компилятором, прежде чем фактически скомпилировать их в объектный код. Эта реализация может быть достигнута только в том случае, если известны аргументы шаблона. Теперь представьте сценарий, в котором функция шаблона объявлена в a.h
, определена в a.cpp
и использована в b.cpp
. Когда a.cpp
компилируется, не обязательно известно, что для предстоящей компиляции b.cpp
потребуется экземпляр шаблона, не говоря уже о том, какой конкретный экземпляр будет. Для большего количества заголовочных и исходных файлов ситуация может быстро усложниться.
Можно утверждать, что компиляторы можно сделать «умнее», чтобы «смотреть в будущее» для всех применений шаблона, но я уверен, что создать рекурсивные или иные сложные сценарии не составит труда. AFAIK, компиляторы не делают такой взгляд вперед. Как указал Антон, некоторые компиляторы поддерживают явные объявления экспорта экземпляров шаблона, но не все компиляторы поддерживают его (пока?).
Здесь много правильных ответов, но я хотел бы добавить это (для полноты):
Если вы, в нижней части файла cpp реализации, сделаете явную реализацию всех типов, с которыми будет использоваться шаблон. компоновщик сможет найти их как обычно.
Редактировать: Добавление примера явного создания шаблона. Используется после определения шаблона и определения всех функций-членов.
template class vector<int>;
Это создаст экземпляр (и, следовательно, сделает доступным для компоновщика) класс и все его функции-члены (только). Аналогичный синтаксис работает для шаблонных функций, поэтому если у вас есть перегрузки операторов, не являющихся членами, вам может потребоваться сделать то же самое для них.
Приведенный выше пример довольно бесполезен, поскольку вектор полностью определен в заголовках, за исключением случаев, когда общий включаемый файл (предварительно скомпилированный заголовок?) Использует extern template class vector<int>
, чтобы не создавать его экземпляры во всех других (1000?) Файлы, которые используют вектор.
Это означает, что самый портативный способ определить реализации метода шаблонных классов состоит в том, чтобы определить их в определении шаблонного класса.
template < typename ... >
class MyClass
{
int myMethod()
{
// Not just declaration. Add method implementation here
}
};
На самом деле до C++ 11 стандарт определил export
ключевое слово, которое будет позволять объявить шаблоны в заголовочном файле и реализовать их в другом месте.
Ни один из популярных компиляторов не реализовал это ключевое слово. Единственный, о котором я знаю, является frontend, записанным проектной группой Edison, которая используется компилятором C++ Comeau. Все другие потребовали, чтобы Вы записали шаблоны в заголовочных файлах, потому что для компилятора уже нужно шаблонное определение для надлежащего инстанцирования (как другие, на которых указывают).
В результате комитет по стандарту C++ ISO решил удалить export
функция шаблонов с C++ 11.