Разница заключается в грамматике C ++. Простая декларация формируется так:
declaration-specifier-seq init-declarator-list
Где объявление-спецификатор-seq представляет собой последовательность спецификаторов объявления:
simple-type-specifier: int, bool, unsigned, typedef-name, class-name ...
class-specifiers: class X { ... }
type-qualifier: const, volatile
function-specifier: inline, virtual, ...
storage-class-specifier: extern, static, ...
typedef
Вы поняли идею. И список инициаторов объявлений - это список деклараторов с необязательным инициализатором для каждого:
a
*a
a[N]
a()
&a = someObj
Таким образом, полное простое объявление может выглядеть следующим образом, содержащее 3 объявления:
int a, &b = a, c[3] = { 1, 2, 3 };
Члены класса имеют специальные правила для учета различного контекста, в котором они появляются, но они очень похожи. Теперь вы можете сделать
typedef int A[3];
A *a;
Так как первый использует спецификатор typedef, а затем простой-type-спецификатор, а затем декларатор типа "a [N]". Во втором объявлении затем используется typedef-name «A» (простой-type-спецификатор), а затем декларатор типа «* a». Тем не менее, вы, конечно, не можете сделать
int[3] * a;
Так как "int [3]" не является допустимым описателем-спецификатора объявления, как показано выше.
И теперь, конечно, шаблон не , как подстановка текста макроса. Конечно, параметр типа шаблона обрабатывается как любое другое имя типа, которое интерпретируется как просто тип, который он называет, и может появляться там, где может появиться спецификатор простого типа. Некоторые люди на C # говорят, что шаблоны C ++ «просто как макросы», но, конечно, это не так:)