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
Related
I was writing functions and came across this situation:
void doSomeThing(std::vector<someType> vec)
{
for(element : vec)
{
// do Something different if it is in vector
}
}
void doSomeThing(someType element)
{
// do Something else if it was not a vector
}
I need them to be separate like above stated. I was wondering if there was a way using templates to deduce the type and do the processing accordingly?
Well, yes, it is possible.
For example, you could do;
template<class someType>
void doSomeThing( const someType &obj )
{
// do something assuming someType is not a vector of something
}
template<class someType>
void doSomeThing( const std::vector<someType> &obj )
{
// do something different if a vector<someType> is passed
}
int main()
{
int x = 24;
std::vector<int> a{1,2,3}; // assuming C++11 and later
doSomeThing(x); // will call a specialisation of the first form above
doSomething(a); // will call a specialisation of the second form above
}
Personally, I'd do it slightly differently though - instead of overloading for a vector, I'd overload for a pair of iterators. For example, assuming doSomething() is just function that prints to std::cout
template<class someType>
void doSomeThing( const someType &obj )
{
std::cout << obj;
}
template<class Iter>
void doSomeThing( Iter begin, Iter end)
{
while(begin != end)
{
std::cout << *begin << ' ';
++begin;
}
std::cout << '\n';
}
which will work with iterators from any standard container (e.g. specialisations of std::vector, std::list) or anything else that can provide a pair of valid iterators.
int main()
{
int x = 24;
std::vector<int> a{1,2,3}; // assuming C++11 and later
std::list<double> b {42.0, 45.0};
doSomeThing(x);
doSomething(std::begin(a), std::end(a));
doSomething(std::begin(b), std::end(b));
}
With just little changes you can do so
#include <iostream>
#include <vector>
template <typename T>
void doSomeThing(std::vector<T> vec)
{
for (element : vec)
{
// do Something different if it is in vector
}
}
template <typename T>
void doSomeThing(T element)
{
// do Something else if it was not a vector
}
For example you can write
template <class T>
void doSomeThing( const std::vector<T> &vec )
{
for ( const auto &element : vec )
{
std::cout << element << ' ';
}
std::cout << '\n';
}
template <class T>
void doSomeThing( const T &obj )
{
for ( const auto &element : obj )
{
std::cout << element << ' ';
}
std::cout << '\n';
}
Here is a demonstration program.
#include <iostream>
#include <vector>
#include <type_traits>
template <class T>
void doSomeThing( const std::vector<T> &vec )
{
std::cout << std::boolalpha
<< std::is_same_v<std::decay_t<decltype( vec )>, std::vector<T>>
<< '\n';
for ( const auto &element : vec )
{
std::cout << element << ' ';
}
std::cout << '\n';
}
template <class T>
void doSomeThing( const T &obj )
{
std::cout << std::boolalpha
<< std::is_same_v<std::decay_t<decltype( obj )>, std::vector<T>>
<< '\n';
for ( const auto &element : obj )
{
std::cout << element << ' ';
}
std::cout << '\n';
}
int main()
{
std::vector<int> v = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
doSomeThing( v );
int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
doSomeThing( a );
}
The program output is
true
0 1 2 3 4 5 6 7 8 9
false
0 1 2 3 4 5 6 7 8 9
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;
}
}
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';
I'm not very familiar with iterators in C++. Basically I have a container, which was written by someone else, which I do populate with records (I create many containers). However, I need to output tuples, instead each container separately as e.g.:
a1 | a2 | ... | an
given that each a's belong to separate containers. I will take as an e.g., a vector container:
vector<int> v;
vector<int>::iterator iter;
v.push_back(1);
v.push_back(2);
v.push_back(3);
for (iter = v.begin(); iter != v.end(); iter++)
cout << (*iter) << endl;
The code above will output records only from one containers, but I need to combine output from many containers (all the same length), how would I go on constructing tuples from all of them?
thanx in advance!
If your project is using Boost already, you could use zip_iterator.
You can also try to implement a simpler version of it (the full implementation is quite complicated).
You can use indices, if container supports random-access, for example
for (size_t i = 0; i < v.size(); ++i)
{
cout << v[i] << " " << v1[i] << endl;
}
You can use many iterators
vector<int>::iterator iter1;
for (iter = v.begin(), iter1 = v1.begin(); iter != v.end(); ++iter, ++iter1)
{
cout << *iter << " " << *iter1 << endl;
}
Further to pmr's answer and your comment thereon seeking a pointer towards implementation, the basic idea for a "zipping" iterator is easy to realise:
#include <iostream>
#include <vector>
template <typename T, typename U>
struct Zip
{
Zip(const T& t, const U& u, char sep = '|')
: it_(t.begin()), iu_(u.begin()), te_(t.end()), ue_(u.end()), sep_(sep)
{ }
Zip& operator*() const { return *this; }
Zip& operator++() { ++it_; ++iu_; return *this; }
operator bool() const { return it_ != te_ && iu_ != ue_; }
friend std::ostream& operator<<(std::ostream& os, const Zip& z)
{
return os << *z.it_ << z.sep_ << *z.iu_;
}
private:
typename T::const_iterator it_, te_;
typename U::const_iterator iu_, ue_;
char sep_;
};
int main()
{
std::vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
std::vector<std::string> v2;
v2.push_back("one");
v2.push_back("two");
v2.push_back("three");
v2.push_back("four");
for (Zip<std::vector<int>, std::vector<std::string> > zip(v1, v2); zip; ++zip)
std::cout << zip << '\n';
}
You could create a Zip iterator with one/both sides being a Zip iterator to handle more (than 2) iterators, or generalise the above using variadic templates.
vector<int> v;
set<float> v2;
vector<int>::iterator iter;
set<float>::iterator iter2;
for (iter = v.begin(), iter2 = v2.begin();
iter != v.end() && iter2 != v2.end();
++iter, ++iter2)
cout << (*iter) << (*iter2) << endl;
Keep in mind that this loop iterates at most as much as the length of the smallest container.
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;
}