Я узнал, что структуры данных могут быть созданы с использованием шаблонов следующим образом:
template<typename T>
struct X {
T weight;
int age;
};
Функции также могут использовать шаблоны следующим образом:
template <class T>
T func_name(int age, T human) {
something_here;
}
Одно из отличий s в том, что в первом случае мы используем typename
в то время как во втором случае мы используем class
,
Я нашел код, который содержит следующее:
template<typename S, typename T>
bool is_null(const row<T>& r)
Итак, я не могу понять, почему мы используем typename
(и не class
) в сочетании с функциями. Разве мы не должны использовать class
?
В этом контексте нет технической разницы между ключевым словом typename
и ключевое слово class
, Это просто вопрос стиля. Смысл ваших первых двух примеров кода не изменится ни на один бит, если они начнутся с template<class T> struct X
а также template <typename T> T func_name(int age, T human)
, (Я склонен использовать class
когда я имею в виду, что параметр шаблона должен быть классом, а не чем-то вроде int
.)
когда template
был впервые представлен, разрешено только существующее ключевое слово class
в качестве индикатора «это аргумент шаблона». Поскольку это становится довольно глупым, когда аргумент шаблона на самом деле не является классом (указатель на функцию, целочисленный тип или какой-либо другой тип «не класс»), typename
был введен, чтобы сделать более ясным, что template<typename T> struct something { T x; };
позволяет something<int> a;
так же как something<name_of_class> a;
,
Для всех намерений и целей, class
а также typename
в случае шаблонов параметры являются взаимозаменяемыми, и это просто вопрос стиля, который вы выбираете делать [большинство людей, вероятно, предпочитают, если вы придерживаетесь одного, не смешивая два — или, возможно, используйте class
когда тип ДОЛЖЕН быть классом, и typename
когда это может быть «любой» тип].
В контексте определения параметров шаблона ключевые слова typename
а также class
являются синонимами.
Почти у каждого есть соглашение, которое они имеют тенденцию придерживаться. Я лично предпочитаю всегда использовать class
здесь и зарезервировать typename
Ключевое слово для его другого использования.
Другое использование для typename
является устранение неоднозначности зависимого типа в определении или объявлении шаблона.
Вот пример из википедия:
template <typename T>
void foo(const T& t)
{
// declares a pointer to an object of type T::bar
T::bar * p;
}
struct StructWithBarAsType {
typedef int bar;
};
int main() {
StructWithBarAsType x;
foo(x);
}
Если вы внимательно посмотрите, вы заметите в строке T::bar * p;
, bar
зависит от параметра шаблона T
что неоднозначно для компилятора как bar
может быть типом или значением в зависимости от контекста типа T
используется для создания шаблона. По умолчанию лечить bar
в качестве значения, поэтому смысл будет умножать T::bar
от p
что не то, что мы хотим.
Решение состоит в том, чтобы квалифицировать зависимый тип с typename
ключевое слово.
typename T::bar * p;
Это предупреждает компилятор о том, что мы намерены лечить bar
как тип.
Есть только одно место, где они отличаются (при объявлении параметров шаблона), и это при использовании шаблона-шаблона.
Ниже четко определен C ++
template <template <typename> class TT> struct example_one {};
пока это не
template <template <typename> typename TT> struct example_two {};
Так как кажется, что вы только начинаете с C ++ / templates, этот угловой случай не будет вас беспокоить некоторое время 🙂 Помимо вышесказанного, шаблон класса, шаблон функции не имеет значения: typename и class синонимы.