Почему структуры не допускаются в определениях шаблонов?

Следующий код дает ошибку error: ‘struct Foo’ is not a valid type for a template constant parameter:

template <struct Foo>
struct Bar {

};

Почему это так?

template <class Foo>
struct Bar {

};

работает отлично и даже принимает конструкцию как аргумент.

Ответ 1

Это просто артефакт правил синтаксиса - синтаксис позволяет использовать ключевые слова class или typename для указания параметра шаблона типа. В противном случае параметр должен быть параметром шаблона "не-тип" (в основном интеграл, указатель или ссылочный тип).

Я полагаю, что Stroustrup (и кто бы он ни был, возможно, взял на себя вход) решил, что нет необходимости включать struct в качестве ключевого слова aa, чтобы указать параметр шаблона типа, поскольку не было необходимости в обратной совместимости с C.

На самом деле, мое воспоминание (мне нужно будет сделать некоторую книгу, когда я вернусь домой) заключается в том, что, когда typename был добавлен, чтобы указать параметр типа шаблона, Stroustrup имел бы любил убирать с помощью ключевое слово class для этой цели (поскольку это было запутанно), но было слишком много кода, который опирался на него.


Edit:

Оказывается, история больше похожа на (от запись блога Стэном Липпманом):

Причиной для двух ключевых слов является исторические. В исходном шаблоне спецификации, Stroustrup повторно использовал существующее ключевое слово класса, чтобы указать типа, а не ввести новое ключевое слово, которое, конечно, может сломаться существующих программ. Дело не в том, что новое ключевое слово не рассматривалось - просто что он не считается необходимым учитывая его потенциальное нарушение. И вверх до стандарта ISO-С++, это было единственный способ объявить тип Параметр.

Повторение существующих ключевых слов кажется всегда сеять путаницу. Мы обнаружили, что что новички [удивлялись] является ли использование класса ограниченный или ограниченный тип аргументы, которые пользователь может указать типа, а не, скажем, встроенный или указательный тип. Так что было какое-то ощущение, что введено новое ключевое слово ошибка.

Во время стандартизации определенные конструкции были обнаружены в пределах определение шаблона, хотя они имели в виду для обозначения деклараций

...

Комитет решил, что новый ключевое слово было всего лишь билетом, чтобы получить компилятор с его неудачной одержимостью с выражениями. Новое ключевое слово было самоописательное имя.

...

Поскольку ключевое слово было в платежной ведомости, черт возьми, почему бы не устранить путаницу, вызванную первоначальным решением о повторном использовании ключевое слово класса. Конечно, учитывая обширный объем существующего кода и книг и статей, переговоров и проводки с использованием ключевого слова class, они решил также сохранить поддержку этого использование ключевого слова. Так вот почему у вас есть оба.

Ответ 2

Короткий ответ: template <class Foo> даже принимает union или double - все еще не разрешено вместо class. Однако typename есть. Это так, как был определен синтаксис.

Несколько более длинный ответ: когда шаблоны для С++, где "придумано", в этом месте было ключевое слово, говорящее, что следующий идентификатор будет именем типа. Было решено повторно использовать существующее ключевое слово class. Это было немного запутанно, но общее нежелание вводить больше ключевых слов, потому что они всегда ломают какой-то существующий код, который использовал это как идентификатор, когда это не было ключевым словом.

Позже typename стал ключевым словом по другим причинам, и поскольку он намного лучше подходит, он теперь можно использовать в этом месте: template <typename Foo>. Тем не менее, с миллиардами строк кода, использующих class в этом месте, он должен оставаться действительным для этой цели. Так что теперь оба разрешены.

Как обычно в С++, это создало несколько лагерей относительно того, какое ключевое слово использовать в этом месте. Некоторые придерживаются class, потому что они используют его более десятилетия. Другие предпочитают typename, потому что это намного лучше подходит. Некоторые используют class, когда ожидается, что Foo имеет тип class (доступ к элементам доступен) и typename, когда также могут использоваться встроенные модули.

Ответ 3

Вы можете создать шаблон с помощью struct; однако синтаксис объявления типа шаблона позволяет показывать ключевые слова "class" или "typename", где вы пытаетесь использовать ключевое слово "struct".

Я должен добавить, что вы также можете использовать определенный тип (например, int), если вы хотите создать экземпляр своего шаблона на основе константы времени компиляции или на основе объекта с внешней связью... но это несколько в стороне.

Ответ 4

Поскольку ключевое слово для параметров шаблона - class или typename. Это не ограничивает параметр Foo классом - он может быть любого типа.