Директива @helper
была удалена , поскольку она была неполной и ее текущий дизайн не соответствовал новому «пути ASP.NET 5». Одна из причин заключается в том, что помощники должны быть объявлены в папке App_Code
, в то время как ASP.NET 5 не имеет понятия специальных папок . Поэтому команда решила временно удалить эту функцию.
Вы не можете передать, объявляют "части" классов как этот. Даже если бы Вы могли, Вы должными быть все еще инстанцировать кода где-нибудь, таким образом, Вы могли связаться против него. Существуют способы обработать его, Вы могли сделать себя небольшой библиотекой с инстанцированиями общих контейнеров (например, вектор) и связать их в. Затем необходимо было бы только когда-либо компилировать, например, vector< int> однажды. Для реализации этого, необходимо будет использовать что-то как [1 110], по крайней мере, предполагая, что Вы придерживаетесь g ++ и явно инстанцируете шаблона в своем lib с [1 111]
<час>Так, реальный рабочий пример. Здесь у меня есть 2 файла, a.cpp и b.cpp
a.cpp:
#include <vector> // still need to know the interface
#include <cstdlib>
int main(int argc, char **argv) {
std::vector<int>* vec = new std::vector<int>();
vec->push_back(3);
delete vec;
return EXIT_SUCCESS;
}
Поэтому теперь я могу скомпилировать a.cpp с [1 112]:
g++ -fno-implicit-templates -c a.cpp
Это даст мне a.o. Если я затем, я пытаюсь связать a.o, который я получаю:
g++ a.o
/usr/bin/ld: Undefined symbols:
std::vector<int, std::allocator<int> >::_M_insert_aux(__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, int const&)
void std::_Destroy<int*, std::allocator<int> >(int*, int*, std::allocator<int>)
collect2: ld returned 1 exit status
Отрицательный результат. Таким образом, мы обращаемся к b.cpp:
#include <vector>
template class std::vector<int>;
template void std::_Destroy(int*,int*, std::allocator<int>);
template void std::__uninitialized_fill_n_a(__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, unsigned long, int const&, std::allocator<int>);
template void std::__uninitialized_fill_n_a(int*, unsigned long, int const&, std::allocator<int>);
template void std::fill(__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, int const&);
template __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > > std::fill_n(__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, unsigned long, int const&);
template int* std::fill_n(int*, unsigned long, int const&);
template void std::_Destroy(__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, std::allocator<int>);
Теперь Вы говорите себе, откуда сделал все эти дополнительные шаблонные вещи, прибывшие? Я вижу template class std::vector<int>
, и это прекрасно, но что относительно остальной части его? Хорошо короткий ответ - то, что, эти вещи реализации при необходимости немного грязны, и когда Вы вручную инстанцируете их, следовательно часть этого беспорядка просачивается. Вы, вероятно, задаетесь вопросом, как я даже выяснил то, чего я должен был инстанцировать. Хорошо я использовал ошибки компоновщика ;).
Поэтому теперь мы компилируем b.cpp
g++ -fno-implicit-templates -c b.cpp
, И мы получаем b.o. Соединение a.o и b.o мы можем добраться
g++ a.o b.o
Ура, никакие ошибки компоновщика.
Так, для вхождения в некоторые детали об обновленном вопросе если это - домашний варивший класс, это должно не обязательно быть это грязное. Например, можно разделить интерфейс от реализации, например, сказать, что у нас есть c.h, c.cpp, в дополнение к a.cpp и b.cpp
c.h
template<typename T>
class MyExample {
T m_t;
MyExample(const T& t);
T get();
void set(const T& t);
};
c.cpp
template<typename T>
MyExample<T>::MyExample(const T& t) : m_t(t) {}
template<typename T>
T MyExample<T>::get() { return m_t; }
template<typename T>
void MyExample<T>::set(const T& t) { m_t = t; }
a.cpp
#include "c.h" // only need interface
#include <iostream>
int main() {
MyExample<int> x(10);
std::cout << x.get() << std::endl;
x.set( 9 );
std::cout << x.get() << std::endl;
return EXIT_SUCCESS;
}
b.cpp, "библиотеке":
#include "c.h" // need interface
#include "c.cpp" // need implementation to actually instantiate it
template class MyExample<int>;
Теперь Вы компилируете b.cpp в b.o однажды. Когда a.cpp изменяет Вас, просто должен перекомпилировать это и ссылку в b.o.
Предописания позволяют Вам сделать это:
template <class T> class vector;
Затем можно объявить ссылки на и указатели на vector<whatever>
, не определяя вектор (без включения vector
заголовочный файл). Это работает то же предописаниями регулярных (нешаблон) классы.
проблема с шаблонами в особенности состоит в том, что Вам обычно нужны не только объявление класса, но также и все определения метода в Вашем заголовочном файле (так, чтобы компилятор мог инстанцировать необходимых шаблонов). Явное шаблонное инстанцирование (из которого можно вызвать использование с -fno-implicit-templates
) является обходным решением для этого; можно поместить определения метода в исходный файл (или, следуя примеру Google Style Guide , в -inl.h
заголовочный файл, который Вы не должны включать) затем явно инстанцируют их как это:
template <class int> class vector;
Примечание, в котором Вы на самом деле не нуждаетесь -fno-implicit-templates
для пользы из этого; компилятор тихо постарается не инстанцировать любых шаблонов, для которых он не имеет никаких определений, при условии, что компоновщик поймет это позже. И добавление -fno-implicit-templates
сделает использование весь шаблоны тяжелее (не только трудоемкие), таким образом, я не рекомендовал бы это.
проблема с Вашим примером кода состоит в том, что Вы вперед не объявляете истинное std::vector
класс. Не включая <vector>
, Вы создаете свое собственное, нестандартное vector
класс, и Вы никогда не определяете push_back
, таким образом, нет ничего, чтобы компилятор инстанцировал.
я привык предварительно скомпилированные заголовки для большого эффекта; я не уверен, почему они не помогли Вам. Вы помещаете все свои неизменяющиеся заголовки на сингле all.h
, предварительно скомпилировал его и проверил с [1 113] или подобный, что all.h.pch
был загружен, и отдельные заголовочные файлы не были? (Как использовать strace
: вместо того, чтобы работать g++ mytest.cc
, выполнение strace -o strace.out g++ mytest.cc
, затем просматривают strace.out
в текстовом редакторе и ищут open(
вызовы для наблюдения, какие файлы читаются.)
С предописаниями можно только объявить участников или параметры как указатель или ссылка на тот тип. Вы не можете использовать методы или другие вещи, которые требуют внутренностей упомянутого типа. Это сказало, что я нашел предописания, действительно ограничивающие при попытке ускорить время компиляции. Я предлагаю, чтобы Вы исследовали возможность предварительно скомпилированных заголовков немного больше, так как я нашел, что они действительно помогли со временем компиляции, хотя это было с использованием Visual C++ в Windows и не g ++.
Существует <iosfwd>
, который даст Вам некоторое предописание для iostream классов, но в целом нет очень, можно сделать о шаблонах stl с точки зрения вперед объявления их.
Предварительно скомпилированные заголовки являются способом пойти. Вы не заметите увеличения скорости в первый раз, когда Вы компилируете их, но необходимо только заплатить ту цену однажды в течение каждого раза, когда Вы изменяете предварительно скомпилированный заголовок (или что-либо включенное в него).
Посмотрите этот вопрос для других идей об ускорении компиляции.