error C2760: syntax error: unexpected token '<', expected ';' - c++

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

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++)

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

Related

Why can't I manually define a template parameter?

I have a simple sample which provides:
a struct template:
#include <iostream>
#include <vector>
template <typename T>
struct range_t
{
T b, e;
range_t(T x, T y) : b(x), e(y) {}
T begin() { return b; }
T end() { return e; }
};
a function template:
template <typename T>
range_t<T> range(T b, T e)
{
return range_t<T>(b, e);
}
I can use it to skip items in foreach loop of a (i.e) std::vector:
int main()
{
std::vector<int> v{ 1, 2, 3, 4 };
for (auto p : range(v.begin()+1, v.end()))
{
std::cout << p << " ";
}
}
This works as intended, however I don't really understand the need of the function template (2).
I tried to write the foreach loop as this:
for (auto p : range_t<std::vector::const_iterator>(v.begin()+1, v.end()))
But for this I always got
error: template argument 1 is invalid
This might be a duplicate question, feel free to mark it as duplicate and please let me know the duplicated question which answers to all of these questions:
Why is the template argument invalid here?
(How) can I skip the function template?
How can I create a function template which would work as this:
myskipper would get only v as parameter in the foreach loop:
template<typename T>
range_t<T::const_iterator> myskipper(T c) {
return range_t<T::const_iterator>(c.begin()+1, c.end());
}
...
for (auto p : myskipper(v)) ...
Based on the comments and this article about iterator overflow, here a complete working example:
#include <iostream>
#include <vector>
template <typename T>
struct range_t
{
T b, e;
range_t(T x, T y) : b(x), e(y) {}
T begin() { return b; }
T end() { return e; }
};
template <typename T>
range_t<T> range(T b, T e)
{
return range_t<T>(b, e);
}
template<typename T>
range_t<typename T::iterator> skip(T &c, typename T::size_type skipCount)
{
return range_t<typename T::iterator>(c.begin() + std::min(c.size(), skipCount), c.end());
}
int main()
{
std::vector<int> v{ 1, 2, 3, 4 };
for (auto p : range(v.begin()+1, v.end()))
{
std::cout << p << " ";
}
std::cout << std::endl;
for (auto p : range_t(v.begin()+1, v.end()))
{
std::cout << p << " ";
}
std::cout << std::endl;
for (auto p : skip(v, 3))
{
std::cout << p << " ";
}
std::cout << std::endl;
}

error: no matching function for call when compiled

I am trying to write a simple C++ function using iterator for a vector as follows:
#include <iostream>
#include<vector>
#include<sstream>
using namespace std;
using vit = vector<string>::iterator;
void print(const vector<string>& s) {
for(vit it = s.begin(); it != s.end(); ++it ){
cout << *it << endl;
}
}
int main() {
std:: vector<int> v;
for(int i = 0; i < v.size(); ++i)
v[i] = 5 - i;
print(v);
return 0;
}
But I get a list of error including:
error: no matching function for call to print
I thought it might be because I used iterator instead of const_iterator, but the error persists after I fixed it. Why is that happening? Thanks!
print() only accepts an std::vector<string>. You're passing an std::vector<int> which is not the same thing.
If you want to be able to pass any std::vector you want, you'll need to create a template:
template <class type>
void print(const vector<type>& s) {
for(auto it = s.begin(); it != s.end(); ++it ){ // vit is only for a std::vector<string>
cout << *it << endl;
}
}
If you're attached to using vit, you could make that a template as well:
template <class type>
using vit = vector<type>::iterator;
template <class type>
void print(const vector<type>& s) {
for(vit<type> it = s.begin(); it != s.end(); ++it ){ // vit now works with any type
cout << *it << endl;
}
}

Template print function C++

so far I wrote this:
template <typename TType>
void print_vector(const std::vector<TType>& vec)
{
typename std::vector<TType>::const_iterator it;
std::cout << "(";
for(it = vec.begin(); it != vec.end(); it++)
{
if(it!= vec.begin()) std::cout << ",";
std::cout << (*it);
}
std::cout << ")";
}
template<>
template <typename T2>
void print_vector(const std::vector< std::vector<T2> >& vec)
{
for( auto it= vec.begin(); it!= vec.end(); it++)
{
print_vector(*it);
}
}
The first function works fine for things like std::vector< double> and so on. Now I want to be able to print std::vector< std::vector< TType>> things as well. The second part doesn't compile, but that's the "idea" I have of solving my task. Any suggestions on how to achieve that kind of behavior?
Compilation Error: too many template-parameter-lists
Remove the template<> part, function template overloading would work fine.
template <typename TType>
void print_vector(const std::vector<TType>& vec)
{
typename std::vector<TType>::const_iterator it;
std::cout << "(";
for(it = vec.begin(); it != vec.end(); it++)
{
if(it!= vec.begin()) std::cout << ",";
std::cout << (*it);
}
std::cout << ")";
}
template <typename T2>
void print_vector(const std::vector< std::vector<T2> >& vec)
{
for( auto it= vec.begin(); it!= vec.end(); it++)
{
print_vector(*it);
}
}
You may actually want to go for a more generic solution to the problem, allowing to print pretty much any iterable type:
#include <vector>
#include <iostream>
template <typename Iterable>
std::ostream& operator<<(std::ostream& os, const Iterable& vals)
{
for (const auto& val : vals)
os << val << std::endl;
return os;
}
int main()
{
auto simple_vec = std::vector<int>{3, 5 , 7};
std::cout << simple_vec;
auto nested_vec = std::vector<std::vector<int>>{{1, 2}, {3, 4}};
std::cout << nested_vec;
}
For further improvements on this solution, you could try using SFINAE, to make sure the templated << is only available for iterable types.
If you make your function to print base types and override for vector using itself recursively:
template<typename T>
void print( const T &t )
{
std::cout << t;
}
template<typename T>
void print( const std::vector<T> &v )
{
std::cout << '[';
for( auto it = v.begin(); it != v.end(); ++it ) {
if( it != v.begin() ) std::cout << ',';
print( *it );
}
std::cout << ']';
}
then you do not need to write special one for vector of vectors or vector of vectors of vectors and so on.
live example

Keep getting "no match for 'operator<<' C++

I'm writing a program to read text from a file and I need to print out the position that each of the numbers appear in the file. For example, the .txt file looks like this:
one
two one two
three three two one
and my output should look like:
one: 0, 2, 7
two: 1, 3, 6
three: 4, 5
Everything works fine until I try to display the map of type string, list(int), then I get the whole ""no match for 'operator<<'" error.
Here is my code, any help would be greatly appreciated, thanks!
#include <iostream>
#include <fstream>
#include <string>
#include <map>
#include <list>
#include <vector>
using namespace std;
int main()
{
ifstream is("input.txt");
if (is.fail())
{
cout << "File I/O error!" << endl;
exit(1);
}
map<string, list<int> > m;
string word;
vector<string> v;
list<int> l, x, y;
while (is >> word)
{
v.push_back(word);
}
for (unsigned int i = 0; i < v.size(); ++i)
{
if (v[i] == "one")
l.push_back(i);
else if (v[i] == "two")
x.push_back(i);
else if (v[i] == "three")
y.push_back(i);
}
m["One"] = l;
m["Two"] = x;
m["Three"] = y;
for (map<string, list<int> >::iterator i = m.begin(); i != m.end(); ++i)
cout << (*i).first << ", " << (*i).second << endl;
return 0;
}
The problem is when you try to output (*i).second. As i is of type map<string, list<int> >::iterator (*i).second is a list<int> and c++ does not know how to output it.
You have two options - either overload ostream& operator<<(ostream& out, const list<int>& l) or use an inner cycle to output the elements one by one. I personally recommend the second option as overloading the operator for such "popular" type may be dangerous.
The simplest solution:
// !!! DO NOT DO THIS AT HOME OR AT ALL !!!
namespace std {
template <typename T, typename A>
ostream& operator<<(ostream& out, list<T, A> const& l) {
if (l.empty()) { return out << "[]"; }
out << '[';
bool first = true;
for (auto const& t: l) {
if (first) { first = false; } else { out << ", "; }
out << t;
}
return out << ']';
} // operator<<
} // namespace std
Unfortunately... it is strictly forbidden to do so (you are only allowed to specialize existing templates in the std namespace, not add any overload).
Therefore, the best standard compliant solution is to:
Declare a new stream of your own (which forwards everything to a std::ostream&)
Overload this operator for your new stream (in its namespace)
Only ever use this new stream afterward
Feel free to bitch at the clumsiness...
Example of custom stream to get you started:
namespace project {
class OStream {
public:
explicit OStream(std::ostream& out): _out(out) {}
template <typename T>
OStream& operator<<(T const& t) { print(*this, t); return *this; }
template <typename T>
void push(T const& t) { _out << t; }
private:
std::ostream& _out;
}; // class OStream
// Generic Operator (directly forwards to `std::ostream`)
template <typename T>
void print(OStream& out, T const& t) { out.push(t); }
// STL Containers
template <typename It>
void print_range(OStream& out, It begin, It end) {
if (begin == end) { out << "[]"; return; }
out << '[' << *begin;
for (++begin; begin != end; ++begin) { out << ", " << *begin; }
out << ']';
} // push_range
template <typename T, typename A>
void print(OStream& out, std::list<T, A> const& l) {
print_range(out, l.begin(), l.end());
} // operator<<
} // namespace project
// usage
int main() {
std::list<int> example = { 1, 2, 3, 4 };
project::OStream(std::cout) << example << "\n";
}
Note: there are other solutions than creating a custom stream, such as copy pasting std::copy(example.begin(), example.end(), std::ostream_iterator<int>(std::cout, ", ")); everywhere you need to print a list, but I am yet to meet another handy one.

Generic Iterators to access vectors

I would like to know if I can have a generic iterator to access the elements in the the vectors. I have for different vectors but only one function to display the elements.
If I can have a generic iterator than my method can work out smoothly. Please advice if it is possible.
Point2,Point3,Line2,Line3 are 4 different classes. The method takes in a vector object which I have created in another method.
template <typename VecObject>
void Display(VecObject v) {
if (filterCriteria == "Point2") {
vector<Point2>::iterator it;
} else if (filterCriteria == "Point3") {
} else if (filterCriteria == "Line2") {
} else if (filterCriteria == "Line3") {
}
for ( it = v.begin(); it!=v.end(); ++it) {
cout << *it << endl;
}
}
This what i used to do ealier and it work find. I now need to to implement using iterators
//for (int i = 0; i < v.size(); i++) {
// cout << v[i];
// }
You have access to a vector's iterator types via iterator and const_iterator, so you need no switching:
template <typename VecObject>
void Display(const VecObject& v) {
typename VecObject::const_iterator it;
for ( it = v.begin(); it!=v.end(); ++it) {
cout << *it << endl;
}
}
Note that I changed the signature to take a const reference as opposed to a value. With the original signature, you would be needlessly copying the vector each time you call the function.
Alternatively, you can implement the function to take two iterators:
template <typename Iterator>
void Display(Iterator first, Iterator last) {
for (Iterator it = first; it!=last; ++it) {
cout << *it << endl;
}
}
and call it like this:
Display(v.begin(), v.end());
template<typename VectorObject>
void Display(VecObject v) {
typename VectorObject::const_iterator it = v.begin();
for (; it!=v.end(); ++it) {
cout << *it << endl;
}
}
Assume that your VectorObject implements iterators you can access to it's iterator type directly.
Usage:
int main()
{
std::vector<int> intv(2, 5);
std::vector<float> fv(2, 10);
Display(intv);
Display(fv);
return 0;
}