Здесь много правильных ответов, но я хотел добавить это (для полноты):
Если вы в нижней части файла cpp реализации выполняете явное инстанцирование всех типов, которые будут использоваться шаблоном с, компоновщик сможет найти их как обычно.
Изменить: добавление примера явного создания экземпляра шаблона. Используется после того, как шаблон определен, и определены все функции-члены.
template class vector<int>;
Это создаст экземпляр (и, следовательно, сделает доступным для компоновщика) класс и все его функции-члены (только). Подобный синтаксис работает для функций шаблона, поэтому, если у вас есть перегрузки операторов, не являющихся членами, вам может понадобиться сделать то же самое для них.
Вышеприведенный пример бесполезен, поскольку вектор полностью определен в заголовках, за исключением случаев, когда common include file (precompiled header?) использует extern template class vector<int>
, чтобы не создавать его из всех других (1000?) файлов, которые используют вектор.
Grrr. Единственная причина этой функции для существования состоит в том, чтобы использовать в своих интересах инструкцию ЦП для этого, и они даже не сделали этого!
Ничего себе, это действительно выглядит глупым, не так ли?
проблема состоит в том, что - согласно книге Microsoft Press ".NET Ассемблер IL" Lidin - rem IL и отделение atithmetic инструкции точно что: вычислите остаток и вычислите делитель.
Все арифметические операции кроме операции отрицания берут два операнда от стека и помещают результат на стек.
, По-видимому, способ, которым разработан ассемблерный язык IL, не возможно иметь инструкцию IL, которая производит два вывода и продвигает их на стопку оценки. Учитывая, что ограничение, у Вас не может быть инструкции подразделения в ассемблере IL, который вычисляет обоих путь, x86 DIV или инструкции IDIV делают.
IL был разработан для безопасности, verifiability, и устойчивости, НЕ для производительности. Любой, кто имеет вычисление - интенсивное приложение и заинтересован, прежде всего, с производительностью, будет использовать собственный код и не.NET.
я недавно посетил Супервычисления '08, и на одном из технических семинаров, евангелист для Microsoft Compute Server дал грубое эмпирическое правило, что.NET обычно была половиной скорости собственного кода - который точно имеет место здесь!.
Ответ, вероятно, что никто не думал это приоритет - это достаточно хорошо. То, что это не было зафиксировано ни с какой новой версией Платформы.NET, является индикатором того, как редко это используется - скорее всего, никто никогда не жаловался.
Если бы я должен был взять произвольное предположение, то я сказал бы это, кто бы ни реализовал Математику. DivRem понятия не имел, что x86 процессоры способны к выполнению его в единственной инструкции, таким образом, они записали это как две операции. Это - не обязательно плохая вещь, если оптимизатор работает правильно, хотя это - еще один индикатор, в котором знание низкого уровня печально испытывает недостаток в большинстве программистов в наше время. Я ожидал бы, что оптимизатор свернет модуль и затем разделит операции на одну инструкцию и людей, которые пишут, оптимизаторы должны знать эти виды вещей низкого уровня...
Кто-либо еще получает противоположное при тестировании этого?
Math.DivRem = 11.029 sec, 11.780 sec
MyDivRem = 27.330 sec, 27.562 sec
DivRem = 29.689 sec, 30.338 sec
FWIW, я выполняю Intel Core 2 Duo.
числа выше были с отладочная сборка...
Со сборкой конечных версий:
Math.DivRem = 10.314
DivRem = 10.324
MyDivRem = 5.380
Похож на команду IL "rem", менее эффективно, чем "mul, sub" комбинация в MyDivRem.
Эффективность может зависеть от включенных чисел. Вы тестируете КРОШЕЧНУЮ часть доступного пространства задач и всех загруженных с передней стороны. Вы проверяете первый 1 миллион * 10 = 1 миллиард непрерывных входных комбинаций, но фактическое пространство задач является приблизительно 4,2 миллиардами, в квадрате, или 1.8e19 комбинации.
выполнение общих математических операций библиотеки как это должно быть амортизировано по целому пространству задач. Мне было бы интересно видеть результаты более нормализованного входного распределения.
Вот мои числа:
15170 MyDivRem
29579 DivRem (same code as below)
29579 Math.DivRem
30031 inlined
тест был немного изменен; я добавил присвоение на возвращаемое значение и выполнял сборку конечных версий.
Core 2 Duo 2.4
Мнение:
Вы, казалось, нашли хорошую оптимизацию ;)
Это находится частично в природе зверя. Нет насколько я знаю никакого общего быстрого способа вычислить остаток от подразделения. Это собирается взять соответственно большое количество тактов, даже с x сто миллионов транзисторов.
Я предполагаю, что большая часть дополнительных затрат связана с установкой и отключением вызова статического метода.
Что касается того, почему он существует, я бы предположил, что он существует отчасти для полноты и отчасти для пользы других языков, которые могут иметь нелегкие в использовании реализации целочисленного деления и вычисления модуля.