Ну, в общем, шаблоны C ++ и дженерики C # похожи - по сравнению с дженериками Java, которые полностью отличаются, но они также имеют большие различия. Как и в C #, существует поддержка во время выполнения с помощью отражения, получая объект, описывающий типы, используемые для создания экземпляров обобщений. C ++ не имеет отражения, и все, что он делает с типами, делается во время компиляции.
Самое большое различие между шаблонами C # и шаблонами C ++ заключается в том, что шаблоны C # лучше проверяются на тип. Они всегда ограничены в том смысле, что они не допускают операций, которые не указаны как действительные во время определения обобщений. Главный дизайнер C # поднял в качестве причины того, что дополнительная сложность, которую он принял бы, подразумевала ограничения. Я не очень разбираюсь в C #, поэтому я не могу говорить здесь дальше. Я расскажу о том, как обстоят дела в C ++ и как они будут улучшаться, чтобы люди не думали, что все в C ++ неправильно.
В C ++ шаблоны не ограничены. Если вы выполняете операцию, во время определения шаблона подразумевается, что операция завершится успешно во время создания экземпляра. Компилятору C ++ даже не требуется синтаксически проверять шаблон на валидность. Если он содержит синтаксическую ошибку, то эта ошибка должна быть диагностирована при создании экземпляра. Любая диагностика до этого является чистой полезностью реализации.
Эти подразумеваемые ограничения показали, что они могут быть простыми для дизайнера шаблонов в краткосрочной перспективе, потому что им не нужно заботиться о указании допустимых операций в их интерфейсе шаблона. Они ложатся бременем на пользователя своего шаблона - поэтому пользователь должен убедиться, что он выполняет все эти требования. Часто случается, что пользователь пытается выполнить, казалось бы, допустимые операции, но терпит неудачу, при этом компилятор выдает пользователю сотни строк сообщений об ошибках о каком-то неверном синтаксисе или не найденных именах. Поскольку компилятор не может знать, какое ограничение , в частности, было нарушено в первую очередь, он перечисляет все части путей кода, когда-либо задействованных вокруг неисправного места, и все, даже не важные детали, и пользователю придется пролистать ужасный текст сообщения об ошибке.
Это фундаментальная проблема, которую можно решить, просто указав в интерфейсе шаблона или обобщенных элементов, какие свойства должен иметь параметр типа. Насколько мне известно, C # может ограничивать параметр для реализации интерфейса или наследования базового класса. Это решает это на уровне типа.
Комитет C ++ уже давно видел, что необходимо решить эти проблемы, и вскоре (вероятно, в следующем году), C ++ также сможет указать такие явные ограничения ( см. Время- примечание машины ниже ), как в следующем случае.
template<typename T> requires VariableType<T>
T f(T a, T b) {
return a + b;
}
В этот момент компилятор сообщает об ошибке, поскольку записанное выражение не помечено как допустимое в соответствии с требованиями. Это в первую очередь помогает разработчику шаблона написать больше правильного кода , потому что код уже проверен на тип уже в некоторой степени (хорошо, насколько это возможно). Теперь программист может заявить, что требование:
template<typename T> requires VariableType<T> && HasPlus<T, T>
T f(T a, T b) {
return a + b;
}
Теперь это будет компилятор. Компилятор, увидев T
в качестве возвращаемого типа, автоматически подразумевает, что T
является копируемым, поскольку использование T
появляется в интерфейсе, а не в теле шаблонов. Другие требования были изложены с использованием положений требований. Теперь пользователь получит соответствующее сообщение об ошибке, если он использует тип, для которого не определено op+
.
C ++ 1x отделяет требования от типа. Вышесказанное работает как для примитивных типов, так и для классов. В этом смысле они более гибкие, но довольно сложные. Правила, определяющие, когда и когда требования выполняются, длинные ... Вы можете с новыми правилами сказать следующее:
template<typename T> requires MyCuteType<T>
void f(T t) { *t = 10; }
И затем, позвоните f
с int
! Это сработало бы, просто написав концептуальную карту для MyCuteType<int>
, которая учит компилятору, как можно разыменовать int. Это будет очень удобно в таких циклах:
for_each(0, 100, doSomething());
Поскольку программист может сообщить компилятору, как int может удовлетворить концепцию input iterator
, вы могли бы написать такой код на C ++ 1x, если бы вы только написали соответствующую карту концептов, что на самом деле не все это сложно.
Хорошо, хватит с этим. Я надеюсь, что смогу показать вам, что ограничение шаблонов не так уж и плохо, но на самом деле лучше , потому что отношения между типами и операциями с ними в шаблонах теперь известны компилятору. И я даже не писал о axioms
, что является еще одной приятной вещью в концепциях C++1x
. Помните, что это будущие вещи , они еще не выпущены, но это произойдет примерно в 2010 году. Тогда нам придется подождать, пока какой-то компилятор реализует все это:)
ОБНОВЛЕНИЕ ОТ "БУДУЩЕГО"
C ++ 0x концепции были не приняты в проект, но были отклонены в конце 2009 года. Очень жаль! Но, возможно, мы увидим это снова в следующей версии C ++? Будем все надеяться!