У меня компилятор (g++ 10.2.0) сам подсказывает, чего не хватает:
test.cpp: В конкретизации «void Sorts::PrintArray(int) [с T = int]»:
test.cpp:161:21: required from here
test.cpp:118:26: ошибка: зависимое имя «std::__cxx11::list::iterator» разбирается как не тип, но конкретизация дает тип
118 | for (std::list::iterator it = arrayList.begin(); it != arrayList.end(); it++)
| ^~~~~~~~
test.cpp:118:26: замечание: задайте «typename std::__cxx11::list::iterator», если подразумевается тип
И так во во всех четырёх местах с итераторами. Это связано с тем, что std::list::iterator - это не обычный тип, а шаблонный, а по правилам языка С++ требуется указывать, что этот шаблон должен разбираться именно как тип.
Это нужно потому, что не всегда возможно определить, является ли подстановка шаблона типом или значением.
void foo(const T& t)
{
// declares a pointer to an object of type T::bar
T::bar * p;
}
struct StructWithBarAsType
{
typedef int bar;
};
struct StructWithBarAsValue
{
static int bar;
};
Непонятно, T::bar это тип или значение? Если в шаблон передать StructWithBarAsType, то это могло бы быть типом, если StructWithBarAsValue - то значением. Поэтому по умолчанию компилятор принимает такую запись за значение (а раз такого члена iterator в std::vector нет, то компилятор ругается на это), а если указать typename, то он будет знать, что это именно тип.