Использовать 'class' или 'typename' для параметров шаблона? [Дубликат]

492

Возможный дубликат:
С++ различие ключевых слов "typename" и" class in templates

При определении шаблона функции или шаблона класса в С++ можно написать это:

template <class T> ...

или можно написать это:

template <typename T> ...

Есть ли веская причина предпочесть друг другу?


Я принял самый популярный (и интересный) ответ, но реальный ответ кажется "Нет, нет веских оснований предпочитать друг друга".

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

Обратите внимание, однако, что в случае параметров шаблона шаблона требуется использовать class вместо typename. См. user1428839 answer ниже. (Но этот частный случай не относится к предпочтению, это требование языка.) (Также это изменится с помощью c++17)

  • 6
    Я думаю, что в этом случае было бы оправданно собрать все ответы вместе и принять свой собственный новый ответ вместо того, чтобы помещать ответ в текст вопроса.
  • 9
    Это не совсем дубликат. Тот, который спрашивает, когда это предпочтительнее. Другой просит о различиях.
Показать ещё 3 комментария
Теги:
templates

10 ответов

337
Лучший ответ

Стэн Липпман рассказал об этом здесь. Я думал, что это интересно.

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

  • 4
    И не забывайте читать в комментариях, есть ли веская причина использовать «класс», а не «имя типа».
  • 2
    ВОЗРОЖДЕНИЕ! Честно говоря, я не нахожу эту статью особенно ясной. в T::A *obj; язык, насколько я знаю, должен анализировать оператор как декларацию из-за правила декларации: все, что выглядит как объявление, даже если оно неоднозначно выглядит как что-то еще, должно преобразовываться в объявление [0]. Я также не нашел Bjarne Stroustrup ясно об этом. [0] Язык программирования C ++ 3e, Страуструп, Приложение C.13.5, с. 856-858
Показать ещё 4 комментария
256

В соответствии с Скоттом Майерсом, Эффективным С++ (3-е изд.), пунктом 42 (который, конечно же, должен быть окончательным ответом) - разница "ничего".

Совет должен использовать "класс", если ожидается, что T всегда будет классом с "typename", если ожидаются другие типы (int, char * whatever). Рассмотрите его как подсказку использования.

  • 50
    Мне нравится понятие фактора подсказки. Я думаю, что я начну использовать это.
  • 2
    «Шаблоны C ++ Полное руководство» Дэвид Вандевурде Николай М. Хосуттис. 2.1.1
Показать ещё 2 комментария
120

В качестве дополнения ко всем вышеприведенным сообщениям использование ключевого слова class является принудительным (редактировать: до и включая С++ 14) при работе с шаблон шаблона, например:

template <template <typename, typename> class Container, typename Type>
class MyContainer: public Container<Type, std::allocator<Type>>
{ /*...*/ };

В этом примере typename Container создала ошибку компилятора, примерно так:

error: expected 'class' before 'Container'

см. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4051.html для принятия typename в шаблоне шаблона на С++ 14.

  • 4
    Похоже, что Clang 3.5 и Visual Studio 2015 теперь поддерживают имя типа N4051 в параметрах шаблона шаблона.
  • 2
    По крайней мере, на данный момент, это очень важно и делает этот ответ лучше, чем принятый и второй по величине.
38

Я предпочитаю использовать typename, потому что я не поклонник перегруженных ключевых слов (jeez - сколько разных значений имеет static для разных контекстов?).

  • 37
    Конечно, typename также перегружен ....
  • 8
    Это правда, но, похоже, это не так запутанно перегружено - другие варианты использования typename сбивают с толку не столько из-за перегрузки, сколько из-за ситуаций, когда это требуется, довольно запутанно. Другие ключевые перегрузки ( class или static ) кажутся активными участниками путаницы.
Показать ещё 2 комментария
12

Есть разница, и вы должны предпочесть class на typename.

Но почему?

typename является незаконным для аргументов шаблона шаблона, поэтому, чтобы быть последовательным, вы должны использовать class:

template<template<class> typename MyTemplate, class Bar> class Foo { };    //  :(
template<template<class>    class MyTemplate, class Bar> class Foo { };    //  :)
  • 19
    Обратите внимание, что это несоответствие будет исправлено в C ++ 1z.
  • 1
    @MilesRout C ++ 1z == C ++ 17, верно?
Показать ещё 1 комментарий
9

В ответ на Mike B я предпочитаю использовать "класс", поскольку в шаблоне "typename" имеет перегруженное значение, но "класс" не, Возьмите пример проверенного целочисленного типа:

template <class IntegerType>
class smart_integer {
public: 
    typedef integer_traits<Integer> traits;
    IntegerType operator+=(IntegerType value){
        typedef typename traits::larger_integer_t larger_t;
        larger_t interm = larger_t(myValue) + larger_t(value); 
        if(interm > traits::max() || interm < traits::min())
            throw overflow();
        myValue = IntegerType(interm);
    }
}

larger_integer_t является зависимым именем, поэтому для этого требуется 'typename', чтобы синтаксический анализатор мог распознать, что larger_integer_t является типом. class, с другой стороны, не имеет такого перегруженного значения.

Это... или я просто ленив от души. Я набираю "класс" гораздо чаще, чем "typename", и, таким образом, его легче набирать. Или это может быть признаком того, что я пишу слишком много кода OO.

  • 7
    Я не считаю это перегруженным. В обоих случаях typename делает то же самое: это означает, что за ним следует тип вместо переменной.
  • 4
    Но за «typedef» всегда следует тип, так почему здесь требуется «typename»? Я могу понять, что это требуется в чем-то вроде typename qwert::yuiop * asdfg; при необходимости сообщить парсеру, что это объявление указателя, а не выражение умножения. Но в typedef такой двусмысленности нет.
Показать ещё 2 комментария
6

Просто чистая история. Цитата от Стэна Липпмана:

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

Но нужно использовать typename, а не class! См. Ссылку для получения дополнительной информации, но подумайте о следующем коде:

template <class T>
class Demonstration { 
public:
void method() {
   T::A *aObj; // oops ...
};
6

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

  • 0
    Ну, другой может поспорить, что возможность использовать «класс» делает его похожим, что класс можно использовать только для классов, и поэтому «имя типа» ограничивается примитивными типами. Так что этот аргумент является своего рода субъективным ...
  • 0
    Можно отметить, что каждое имя class является именем typename , но не каждое typename class именем class . Если рассматривать это исключительно, есть два логических подхода: 1) Всегда использовать typename , за исключением случаев, когда используются параметры шаблона шаблона в коде, предшествующем C ++ 17, или 2) Использовать class если параметр явно должен быть пользовательского типа. или typename в других ситуациях. Конечно, реальный мир не такой черно-белый, как этот, и есть также веские аргументы в пользу использования class over typename , поэтому лучше использовать тот, который вам или вашей команде наиболее удобен.
Показать ещё 1 комментарий
1

Насколько я знаю, неважно, какой из них вы используете. Они эквивалентны в глазах компилятора. Используйте то, что вы предпочитаете. Обычно я использую класс.

-2

Расширение комментария DarenW.

После того, как имя и класс не будут отличаться друг от друга, может быть все еще справедливым строгое использование. Используйте класс только в том случае, если это действительно класс, и typename, когда его базовый тип, например char.

Эти типы действительно также принимаются вместо typename

шаблон < char myc = '/' >

который был бы в этом случае даже превосходил typename или class.

Подумайте о "хитрости" или разборчивости для других людей. И на самом деле подумайте, что стороннее программное обеспечение/скрипты могут попытаться использовать код/​​информацию, чтобы угадать, что происходит с шаблоном (подумайте о swig).

Ещё вопросы

Сообщество Overcoder
Наверх
Меню