Reputation: 51
using VS2017 and the code:
template <typename T>
void showset(vector<T> v)
{
for (vector<T>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it;
}
cout << endl;
}
the error is :
error C2760: syntax error: unexpected token , expected ';'
The question is how to use the iterator of template
Upvotes: 4
Views: 6620
Reputation: 5710
First note that if referring to a template argument dependent name like vector<T>::iterator
here, then you need to put typename
prior. Furthermore, depends on what T
is, this would only compile if std::cout
's operator<<
is accepting this T
. This, for example, compiles just fine:
#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;
}
With the auto
-enhanced syntax of C++11, showset()
could be written like this, and then the typename
has no use : )
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;
}
Also since C++11, you can use the range-based for loop to achieve the same as in your original snippet:
template <typename T>
void showset(std::vector<T> v)
{
for (auto& ref : v)
{
std::cout << ref;
}
std::cout << std::endl;
}
As with the lase version, because you're not referring here to the iterator
type there's nothing to put typename
for.
Do note that in both versions you are taking parameter v
by value. Hence, you're copying the entire vector for each function call. As the code is given in the question, there seem to be no reason for this and so you should be passing it by reference, and make it a const
one too as you're not modifying v
anywhere inside of showset()
:
void showset(const std::vector<T>& v);
and then in the non-range-based for loop version don't forget to change the loop statement accordingly:
for (typename std::vector<T>::const_iterator it = v.begin(); it != v.end(); it++)
Upvotes: 6
Reputation: 37607
The good aproch to this looks like this:
template <typename T>
void showset(const T& v)
{
for (auto const &x : v)
{
cout << x;
}
cout << endl;
}
Or without range loop:
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 };
}
So later I can do that:
cout << "Main containter is: " << LogContainer(v) << '\n';
Upvotes: 2