В чем разница между параметрами шаблона "typename" и "class"?
У меня возникли вопросы по поводу использования шаблонов в C++. Я заметил, что в объявлениях шаблонов используются два различных синтаксиса:
template < typename T >
template < class T >
В чем разница между ними?
Кроме того, в приведенном ниже примере (из статьи на немецком Wikipedia о шаблонах) я хотел бы понять, что именно означает каждое из ключевых слов:
template < template < typename, typename > class Container, typename Type >
class Example
{
Container< Type, std::allocator< Type > > baz;
};
Буду признателен за объяснения и примеры!
5 ответ(ов)
В C++, typename
и class
могут использоваться взаимозаменяемо в базовых случаях при указании шаблона:
template<class T>
class Foo
{
};
и
template<typename T>
class Foo
{
};
являются эквивалентными.
Тем не менее, есть специфические случаи, где между typename
и class
существует разница.
Первый случай касается зависящих типов. typename
используется для указания на то, что вы обращаетесь к вложенному типу, который зависит от другого параметра шаблона, например, typedef
в данном примере:
template<typename param_t>
class Foo
{
typedef typename param_t::baz sub_t;
};
Второй случай, который вы, возможно, показываете в своем вопросе, хотя и не осознаете этого:
template < template < typename, typename > class Container, typename Type >
При указании шаблона шаблонов ключевое слово class
ДОЛЖНО использоваться, как показано выше — оно не является взаимозаменяемым с typename
в этом случае (примечание: с C++17 оба ключевых слова разрешены в этом случае).
Также необходимо использовать class
, когда вы явным образом инстанциируете шаблон:
template class Foo<int>;
Я уверен, что есть и другие случаи, которые я мог упустить, но суть в том, что эти два ключевых слова не эквивалентны, и это некоторые распространенные случаи, когда нужно использовать то или иное.
При именовании параметров шаблона typename
и class
эквивалентны. В разделе 14.1.2 указано:
В шаблонном параметре между
class
иtypename
нет семантической разницы.
Однако typename
также используется в другом контексте - чтобы указать компилятору, что вы имеете в виду зависимый тип. В разделе 14.6.2 указано:
Имя, используемое в объявлении или определении шаблона, которое зависит от параметра шаблона, предполагается не указывает на тип, если при применимом поиске имени не найдено имя типа или если имя не квалифицировано ключевым словом
typename
.
Пример:
typename some_template<T>::some_type
Без использования typename
компилятор не может однозначно определить, ссылаетесь ли вы на тип или нет.
Хотя с технической точки зрения разницы нет, я замечал, что эти два варианта используются для обозначения слегка различных вещей.
Для шаблона, который должен принимать любой тип в качестве T, включая встроенные типы (например, массивы), используется:
template<typename T>
class Foo { ... }
А для шаблона, который будет работать только в случае, если T является настоящим классом, используется:
template<class T>
class Foo { ... }
Тем не менее, имейте в виду, что это исключительно стилистический момент, который некоторые программисты предпочитают. Стандарт не обязывает использовать их именно так, и компиляторы это не контролируют.
- Нет разницы.
- Параметр типа шаблона
Container
сам по себе является шаблоном с двумя параметрами типа.
Нет никакой разницы между использованием <typename T>
и <class T>
; это всего лишь соглашение, принятое среди программистов на C++. Лично я предпочитаю <typename T>
, поскольку это более четко описывает его использование, то есть определение шаблона с конкретным типом.
Обратите внимание: существует одно исключение, когда вам необходимо использовать class
(а не typename
) при объявлении параметра шаблона шаблона:
template <template <typename> class T> class C { }; // корректно!
template <template <typename> typename T> class C { }; // некорректно!
В большинстве случаев вы не будете определять вложенное определение шаблона, поэтому оба варианта будут работать — просто соблюдайте последовательность в использовании.
Где и зачем нужно использовать ключевые слова "template" и "typename"?
Имеет ли ключевое слово 'mutable' какие-либо другие цели, кроме разрешения изменения члена данных в константной функции-члене?
Когда использовать виртуальные деструкторы?
Какова разница между 'typedef' и 'using'?
Циклы в программном обеспечении для семейных деревьев