используя VS2017 и код:
template <typename T>
void showset(vector<T> v)
{
for (vector<T>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it;
}
cout << endl;
}
ошибка:
ошибка C2760: синтаксическая ошибка: неожиданный токен, ожидаемый ‘;’
Вопрос в том, как использовать итератор шаблона.
Во-первых, обратите внимание, что если имеется в виду зависимое имя аргумента шаблона лайк vector<T>::iterator
здесь, то вам нужно положить typename
до. Кроме того, зависит от того, что T
будет компилироваться, только если std::cout
«s operator<<
принимает это T
, Это, например, компилируется просто отлично:
#include <iostream>
#include <vector>
template <typename T>
void showset(std::vector<T> v)
{
for (typename std::vector<T>::iterator it = v.begin(); it != v.end(); it++)
{
std::cout << *it;
}
std::cout << std::endl;
}
struct foo
{
};
int main()
{
showset(std::vector<int>{1,2,3});
//showset(std::vector<foo>{}); // Error: `cout` doesn't take `foo`s.
return 0;
}
С auto
-улучшенный синтаксис C ++ 11, showset()
можно написать так, а затем typename
не имеет смысла 🙂
template <typename T>
void showset(std::vector<T> v)
{
for (auto it = v.begin(); it != v.end(); it++)
{
std::cout << *it;
}
std::cout << std::endl;
}
Также, начиная с C ++ 11, вы можете использовать Диапазон на основе за петля добиться того же, что и в исходном фрагменте:
template <typename T>
void showset(std::vector<T> v)
{
for (auto& ref : v)
{
std::cout << ref;
}
std::cout << std::endl;
}
Как и в версии Lase, потому что вы не имеете в виду здесь iterator
типа нечего ставить typename
за.
Обратите внимание, что в обеих версиях вы принимаете параметр v
по значению. Следовательно, вы копируете весь вектор для каждого вызова функции. Поскольку код приведен в вопросе, кажется, нет никаких причин для этого, поэтому вы должны передать его по ссылке и сделать его const
один, так как вы не модифицируете v
где-нибудь внутри showset()
:
void showset(const std::vector<T>& v);
а затем в нена основе диапазона для цикла версия не забудьте изменить оператор цикла соответственно:
for (typename std::vector<T>::const_iterator it = v.begin(); it != v.end(); it++)
Хороший подход к этому выглядит так:
template <typename T>
void showset(const T& v)
{
for (auto const &x : v)
{
cout << x;
}
cout << endl;
}
Или без петли диапазона:
template <typename T>
void showset(const T& v)
{
for (auto it = std::begin(v); it != std::end(v); ++it)
{
cout << *it;
}
cout << endl;
}
редактировать:
Но я обычно использую что-то более сложное. Более или менее это выглядит так:
template<typename T>
class LogContainerHelper {
LogContainerHelper(const T& v
size_t maxFront,
size_t maxTail)
: mContainer{ v }
, mMaxFront{ maxFront }
, mMaxTail{ maxTail }
{}
std::ostream &printTo(std::ostream &out) const {
// here I usually have something more complex
// depending on mMaxFront and mMaxTail values,
// don't have time to recreate that now
auto it = std::begin(mContainer);
auto end = std::end(mContainer);
out << '[';
if (it != end) {
out << *it;
++it;
}
for (; it != end; ++it)
{
out << ", " << *it;
}
return out << ']';
}
private:
const T &mContainer;
size_t mMaxFront;
size_t mMaxTail;
};
template<typename T>
std::ostream &operator <<(std::ostream &out, const LogContainerHelper<T> &helper) {
return helper.printTo(out);
}
template<typename T>
auto LogContainer(const T& v,
size_t maxFront = std::numeric_limits<size_t>::max(),
size_t maxTail = 0)
-> LogContainerHelper<T> {
return LogContainerHelper<T>{ v, maxFront, maxTail };
}
Итак, позже я могу сделать это:
cout << "Main containter is: " << LogContainer(v) << '\n';