Если Вы хотите сделать что-то усовершенствованное (и безопасный с точки зрения типов), Вы могли бы хотеть смотреть на это: http://www.ibm.com/developerworks/java/library/j-configint/index.html
Невозможно написать реализацию класса шаблона в отдельном файле CPP и компилируйте. Все способы сделать это, если кто-то претендует, являются обходными пусками, чтобы имитировать использование отдельного файла CPP, но практически, если вы намереваетесь написать библиотеку класса шаблонов и распространять его с заголовком и Lib файлами, чтобы скрыть реализацию, это просто невозможно Отказ
Чтобы узнать, почему, давайте посмотрим на процесс компиляции. Файлы заголовка никогда не скомпилированы. Они предварительно назначены. Предварительный код затем расположен в клубе с файлом CPP, который фактически скомпилирован. Теперь, если компилятор должен генерировать соответствующий макет памяти для объекта, необходимо знать тип данных класса шаблона.
На самом деле следует понимать, что класс шаблона не является классом вообще, кроме шаблона для класса Декларация и определение, которое генерируется компилятором во время компиляции после получения информации о типе данных из аргумента. До тех пор, пока макет памяти не может быть создан, инструкции по определению метода не могут быть сгенерированы. Помните, что первый аргумент метода класса - это оператор «Это». Все методы классов преобразуются в индивидуальные методы с названием Mangling и первым параметром, как объект, который он работает. «Этот» аргумент, который фактически рассказывает о размере объекта, который в состоянии укладывания шаблона недоступен для компилятора, если только пользователь не содержит объект с действительным аргументом типа. В этом случае, если вы поместите определения метода в отдельный файл CPP и пытаетесь компилировать его файл объекта не будет сгенерирован с информацией о классе. Компиляция не потерпит неудачу, он генерирует файл объекта, но он не будет генерировать какой-либо код для класса шаблона в объекте. Это причина, по которой линкер не может найти символы в объектных файлах, а сборки выполняется.
Теперь, какая альтернатива скрывает важные детали реализации? Как мы все знаем, что основной целью разделяющего интерфейса от реализации является скрытие деталей реализации в двоичной форме. Это то, где вы должны отделить структуры данных и алгоритмы. Ваш шаблон классов должен представлять только структуры данных, а не алгоритмы. Это позволяет скрывать более ценные детали реализации в отдельных библиотеках классов нетемпературов, классы внутри которых работают на классах шаблона или просто используют их для хранения данных. Класс шаблона фактически будет содержать меньше кода для назначения, Get и установки данных. Остальная часть работы будет выполняться классами алгоритма.
Я надеюсь, что эта дискуссия будет полезна.
Ключевое слово 'export' - это способ отделить реализацию шаблона от объявления шаблона. Это было введено в стандарт C ++ без существующей реализации. Со временем только пара компиляторов фактически реализовали это. Прочтите подробную информацию в статье Inform IT об экспорте
Другой вариант - сделать что-то вроде:
#ifndef _STACK_HPP
#define _STACK_HPP
template <typename Type>
class stack {
public:
stack();
~stack();
};
#include "stack.cpp" // Note the include. The inclusion
// of stack.h in stack.cpp must be
// removed to avoid a circular include.
#endif
Мне не нравится это предложение с точки зрения стиля, но оно может вам подойти.
Поскольку шаблоны компилируются по мере необходимости, это вызывает ограничение для многофайловых проектов: реализация (определение) шаблонного класса или функции должна находиться в том же файле, что и ее объявление. Это означает, что мы не можем разделить интерфейс в отдельном файле заголовка и что мы должны включать интерфейс и реализацию в любой файл, который использует шаблоны.
У вас должно быть все в файле hpp. Проблема в том, что классы на самом деле не создаются до тех пор, пока компилятор не увидит, что они необходимы для какого-то ДРУГОГО файла cpp, поэтому у него должен быть весь код, доступный для компиляции шаблонного класса в то время.
Одна вещь, которая Я стараюсь разделить свои шаблоны на общую, не шаблонную часть (которую можно разделить между cpp / hpp) и часть шаблона, зависящую от типа, которая наследует не шаблонный класс.
Только если вы #include "stack.cpp
в конце stack.hpp
. Я бы рекомендовал этот подход, только если реализация относительно велика, и если вы переименуете файл .cpp в другое расширение, как чтобы отличить его от обычного кода.
Иногда можно скрыть большую часть реализации в файле cpp, если вы можете извлечь общие функции для всех параметров шаблона в класс, не являющийся шаблоном (возможно, небезопасный по типу). Тогда заголовок будет содержать вызовы перенаправления в этот класс. Аналогичный подход используется при борьбе с проблемой «раздувания шаблона».
Если вы знаете, с какими типами будет использоваться ваш стек, вы можете явно создать их экземпляры в файле cpp и сохранить там весь соответствующий код.
Также можно экспортировать их через DLL (!), Но получить правильный синтаксис довольно сложно (специфичные для MS комбинации __declspec (dllexport) и ключевого слова export).
Мы использовали это в библиотеке math / geom, которая использовала шаблоны double / float, но было довольно много кода. (В то время я искал его в Google, но сегодня у меня нет этого кода.)
Нет, это невозможно. Не обошлось и без ключевого слова export
, которого практически не существует.
Лучшее, что вы можете сделать, - это поместить реализации ваших функций в файл «.tcc» или «.tpp» и # включить файл .tcc в конец файла .hpp. Однако это просто косметика; это все равно, что реализовать все в файлах заголовков. Это просто цена, которую вы платите за использование шаблонов.
Это возможно, если вы знаете, какие экземпляры вам понадобятся.
Добавьте следующий код в конец stack.cpp, и он заработает:
template class stack<int>;
Все нешаблонные методы стека будут созданы, и этап связывания будет работать нормально.
Проблема в том, что шаблон не генерирует реальный класс, это просто шаблон , сообщающий компилятору, как генерировать класс. Вам нужно создать конкретный класс.
Простой и естественный способ - поместить методы в файл заголовка. Но есть и другой способ.
В вашем .cpp файле, если у вас есть ссылка на каждый экземпляр шаблона и метод, который вам нужен, компилятор сгенерирует их там для использования во всем вашем проекте.
new stack.cpp:
#include <iostream>
#include "stack.hpp"
template <typename Type> stack<Type>::stack() {
std::cerr << "Hello, stack " << this << "!" << std::endl;
}
template <typename Type> stack<Type>::~stack() {
std::cerr << "Goodbye, stack " << this << "." << std::endl;
}
static void DummyFunc() {
static stack<int> stack_int; // generates the constructor and destructor code
// ... any other method invocations need to go here to produce the method code
}