4

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

Bllue
  • 51
  • 1
  • 3

2 Answers2

6

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++)
Geezer
  • 5,600
  • 18
  • 31
  • @Bllue If you're wondering why not put `using namespace std;` you're welcome to read about it [in here](https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice). – Geezer Sep 18 '18 at 10:49
2

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;
}


Edit:
But I'm usually using something more complex. More or less it looks like this:
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';
Marek R
  • 32,568
  • 6
  • 55
  • 140
  • This is not the same as the OP's `void showset(vector v)` – Geezer Sep 18 '18 at 10:28
  • yes and it is on purpose. This is more universal, it works with any container. – Marek R Sep 18 '18 at 11:37
  • I agree it's more universal, just saying this *universality* may not have been what the OP has intended for. A restriction is also a feature if desired. At least nothing comes to my mind so far as to where he specified it is not the case. – Geezer Sep 18 '18 at 11:41