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.
Related
I am trying to solve a question on leetcode which is finding the top k frequent elements. I think my code is correct but the output for a test case is failing.
Input: [ 4,1,-1,2,-1,2,3]
K=2
My answer comes out to be {1,-1} but the expected is {-1,2}. I am not sure where am i getting wrong.
struct myComp{
constexpr bool operator()(pair<int,int> & a,pair<int,int> &b)
const noexcept
{
if(a.second==b.second)
{
return a.first<b.first;
}
return a.second<b.second;
}
};
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
unordered_map<int,int> mp;
for(int i=0;i<nums.size();i++)
{
mp[nums[i]]++;
}
priority_queue<pair<int,int>,vector<pair<int,int>>,myComp> minheap;
for(auto x:mp)
{
minheap.push(make_pair(x.second,x.first));
if(minheap.size()>k)
{
minheap.pop();
}
}
vector<int> x;
while(minheap.size()>0)
{
x.push_back(minheap.top().second);
minheap.pop();
}
return x;
link: https://leetcode.com/problems/top-k-frequent-elements
In the minheap, pairs of <frequency, element> are being pushed. Since we want to sort these pairs on basis of frequency, we need to compare on the basis of frequency only.
Let's say there are two pairs a and b. Then for normal sorting, the comparison would be :
a.first < b.first;
And for reverse sorting, the comparison would be :
a.first > b.first;
In case of min-heap, we need reverse sorting. Hence, the following comparator makes your code pass all the test cases :
struct myComp
{
constexpr bool operator()(pair<int,int> & a,pair<int,int> &b)
const noexcept
{
return a.first > b.first;
}
};
There are several issues with your code.
Obviously there is somewhere using namespace std; in your code. This should be avoided. You will find many posts here on SO explaining, why it this should not be done.
Then we need to qualify all elements from the std library with std::, which makes the scope very clear.
Next: You do not need your own sorting function. Since you insert the elements from the pair in swapped order into the std::priority_queue, the sorting criteria is valid for the counter part, not for the key value. So, your sorting function was anyway wrong, because it was sorting accodring to "second" and not to "first". But if we have a standard sorting, we do not need a special sorting algorithm. A std::pair has a less-than operator. So, the definition can be simply:
std::priority_queue<std::pair<int, int>> minheap;
Then, your if statement
if(minheap.size()>k)
{
minheap.pop();
}
is wrong. You will allow only k values to be inserted. And this are not necessarily the biggest ones. So, you need to insert all values from the std::unordered map. And then they are sorted.
With some cosmetic changes the code will look like the below:
#include <iostream>
#include <utility>
#include <unordered_map>
#include <vector>
#include <queue>
std::vector<int> topKFrequent(std::vector<int>& nums, size_t k) {
std::unordered_map<int, int> mp;
for (size_t i = 0; i < nums.size(); i++)
{
mp[nums[i]]++;
}
std::priority_queue<std::pair<int, int>> minheap;
for (auto x : mp)
{
minheap.push(std::make_pair(x.second, x.first));
}
std::vector<int> x;
for (size_t i{}; i< k; ++i)
{
x.push_back(minheap.top().second);
minheap.pop();
}
return x;
}
int main() {
std::vector data{ 4,1,-1,2,-1,2,3 };
std::vector result = topKFrequent(data, 2);
for (const int i : result) std::cout << i << ' '; std::cout << '\n';
return 0;
}
An additional solution
#include <iostream>
#include <vector>
#include <algorithm>
#include <unordered_map>
#include <utility>
auto topKFrequent(std::vector<int>& nums, size_t k) {
// Count occurences
std::unordered_map<int, size_t> counter{};
for (const int& i : nums) counter[i]++;
// For storing the top k
std::vector<std::pair<int, size_t>> top(k);
// Get top k
std::partial_sort_copy(counter.begin(), counter.end(), top.begin(), top.end(),
[](const std::pair<int, size_t >& p1, const std::pair<int, size_t>& p2) { return p1.second > p2.second; });
return top;
}
// Test code
int main() {
std::vector data{ 4,1,-1,2,-1,2,3 };
for (const auto& p : topKFrequent(data, 2))
std::cout << "Value: " << p.first << " \t Count: " << p.second << '\n';
return 0;
}
And of course, we do have also the universal solution for any kind of iterable container. Including the definition for type traits using SFINAE and checking for the correct template parameter.
#include <iostream>
#include <utility>
#include <unordered_map>
#include <algorithm>
#include <vector>
#include <iterator>
#include <type_traits>
// Helper for type trait We want to identify an iterable container ----------------------------------------------------
template <typename Container>
auto isIterableHelper(int) -> decltype (
std::begin(std::declval<Container&>()) != std::end(std::declval<Container&>()), // begin/end and operator !=
++std::declval<decltype(std::begin(std::declval<Container&>()))&>(), // operator ++
void(*std::begin(std::declval<Container&>())), // operator*
void(), // Handle potential operator ,
std::true_type{});
template <typename T>
std::false_type isIterableHelper(...);
// The type trait -----------------------------------------------------------------------------------------------------
template <typename Container>
using is_iterable = decltype(isIterableHelper<Container>(0));
// Some Alias names for later easier reading --------------------------------------------------------------------------
template <typename Container>
using ValueType = std::decay_t<decltype(*std::begin(std::declval<Container&>()))>;
template <typename Container>
using Pair = std::pair<ValueType<Container>, size_t>;
template <typename Container>
using Counter = std::unordered_map<ValueType<Container>, size_t>;
// Function to get the k most frequent elements used in any Container ------------------------------------------------
template <class Container>
auto topKFrequent(const Container& data, size_t k) {
if constexpr (is_iterable<Container>::value) {
// Count all occurences of data
Counter<Container> counter{};
for (const auto& d : data) counter[d]++;
// For storing the top k
std::vector<Pair<Container>> top(k);
// Get top k
std::partial_sort_copy(counter.begin(), counter.end(), top.begin(), top.end(),
[](const std::pair<int, size_t >& p1, const std::pair<int, size_t>& p2) { return p1.second > p2.second; });
return top;
}
else
return data;
}
int main() {
std::vector testVector{ 1,2,2,3,3,3,4,4,4,4,5,5,5,5,6,6,6,6,6,7 };
for (const auto& p : topKFrequent(testVector, 2)) std::cout << "Value: " << p.first << " \t Count: " << p.second << '\n';
std::cout << '\n';
double cStyleArray[] = { 1.1, 2.2, 2.2, 3.3, 3.3, 3.3 };
for (const auto& p : topKFrequent(cStyleArray, 2)) std::cout << "Value: " << p.first << " \t Count: " << p.second << '\n';
std::cout << '\n';
std::string s{"abbcccddddeeeeeffffffggggggg"};
for (const auto& p : topKFrequent(s, 2)) std::cout << "Value: " << p.first << " \t Count: " << p.second << '\n';
std::cout << '\n';
double value = 12.34;
std::cout << topKFrequent(value,2) << "\n";
return 0;
}
Developed and tested with Microsoft Visual Studio Community 2019, Version 16.8.2.
Additionally compiled and tested with clang11.0 and gcc10.2
Language: C++17
As an old c99 person, I was often stubled upon the curly brakets initialization. In the `initializer_list`, I have to use {r, i} for a complex number. On the other hand, I have to use (r, i) for `complex` in the istream field. Here, I cut a part of my class that is able to run and give examples under codeblock 20.03 with MinGW 8.1.0.
#ifndef __tMatrix_class__
#define __tMatrix_class__
#include <iostream>
#include <initializer_list>
#include <iomanip>
#include <complex>
#include <sstream>
template <typename T> class tMatrix
{
public:
T *ptr;
int col, row, size;
inline T* begin() const {return ptr;}
inline T* end() const {return this->ptr + this->size;}
inline T operator()(const int i, const int j) const { return ptr[i*col+j]; } // r-value
inline T&operator()(const int i, const int j) { return ptr[i*col+j]; } //l-value
inline tMatrix(): col{0}, row{0}, size{0}, ptr{0} {;}
tMatrix(const int i, const int j): col(j), row(i), size(i*j) {
ptr = new T [this->size] ; }
tMatrix(const std::initializer_list< std::initializer_list<T> > s):tMatrix<T>(s.size(), s.begin()->size())
{
int j = 0;
for (const auto& i : s) { std::copy (i.begin(), i.end(), ptr + j*col); ++j ; }
}
tMatrix(const tMatrix<T>&a) : tMatrix<T>(a.row, a.col)
{
std::copy(a.begin(), a.end(), this->ptr);
}
tMatrix<T>& operator=(tMatrix<T>&&a)
{
this->col = a.col;
this->row = a.row;
delete [] this->ptr;
this->ptr = a.ptr;
a.ptr = nullptr;
return *this;
}
tMatrix<T>& operator=(const tMatrix<T>&a)
{
if (col==a.cpl && row==a.row) std::copy(a.begin(), a.end(), this->ptr);
else { tMatrix<T>&&v(a); *this = std::move(v);}
return *this;
}
tMatrix<T>& operator=(const std::initializer_list<std::initializer_list<T> > a)
{
tMatrix<T> &&v = a;
*this = std::move(v);
return *this;
}
~tMatrix() {delete [] this->ptr;}
void operator<<(const char*s)
{
std::stringstream ss;
ss.str(s);
for (int i=0; i<this->size; i++){
if (ss.good()) ss >> this->ptr[i];
else return;
}
}
}; //end of class tMatrix
template <typename X> std::ostream& operator<<(std::ostream&p, const tMatrix<X>&a)
{
p << std::fixed;
for (int i=0; i<a.row; i++) {
for (int j=0; j <a.col; j++) p << std::setw(12) << a(i, j);
p << std::endl;
}
return p;
}
using CMPLX = std::complex<double>;
using iMatrix = tMatrix<int>;
using rMatrix = tMatrix<double>;
using cMatrix = tMatrix< CMPLX >;
#endif
int main()
{
cMatrix cx(2,2);
cx = { { {1,2},{3,4} }, { {5,6}, {7,8} } };
std::cout << cx << std::endl;
cx << "(1,2) (3,4)";
std::cout << cx << std::endl;
return 0;
}
The above code renders correct format of complex number, and prints
$ ./ttt_mtx_init_fin_tmp.exe
(1.000000,2.000000)(3.000000,4.000000)
(5.000000,6.000000)(7.000000,8.000000)
(1.000000,2.000000)(3.000000,4.000000)
(5.000000,6.000000)(7.000000,8.000000)
But if I use the `()` in the initializer_list and `{}` in the istream filed, the results are all wrong. If I chagned the relavant part of main() to :
cx = { { (1,2),(3,4) }, { (5,6), (7,8) } };
std::cout << cx << std::endl;
cx << "{1,2} {3,4}";
std::cout << cx << std::endl;
Which renders all wrong values (compared with above):
$ ./ttt_mtx_init_fin_tmp.exe
(2.000000,0.000000)(4.000000,0.000000)
(6.000000,0.000000)(8.000000,0.000000)
(2.000000,0.000000)(4.000000,0.000000)
(6.000000,0.000000)(8.000000,0.000000)
I found it is rather confusion. So, my questions: is there a way to make these two expressions a same form? Many thanks for any helps.
I do not know any way to make std::istream::operator>> use { and } for std::complex, but if you are fine with using a helper, then you can replace the () in the input with {} and forward the input to the original operator>>:
#include <iostream>
#include <complex>
#include <sstream>
#include <algorithm>
template <typename T>
struct complex_reader {
std::complex<T>& target;
};
template <typename T>
complex_reader<typename T::value_type> get_complex_reader(T& t){ return {t};}
template <typename T>
std::istream& operator>>(std::istream& in,complex_reader<T> cr){
std::string input;
std::getline(in,input,'}'); // read till `}`
std::replace(input.begin(),input.end(),'{','(');
input += ')';
std::stringstream ss{input};
ss >> cr.target; // call the original >>
return in;
}
int main()
{
std::stringstream ss{"{2,2}"};
std::complex<double> x;
ss >> get_complex_reader(x);
std::cout << x;
}
Output:
(2,2)
However, you would have to write a similar helper to get consistent output (you may not provide an operator<< for std::complex<T> directly). Also note that the above implementation is a little simplistic. It reads from the stream until it encounters a }. For invalid input this may result in undesired effects and more sophisticated input validation is required.
Note that the operator>> takes the complex_helper by value to allow passing temporaries. Thats fine, because the member is a (non-const) reference.
This is not an answer, but a reasoning of my choice. After a series of cross conversions with `largest_prime_is_463035818`, I figured out what is my best choice for now (many thanks to his time and patience). A bottom line is becoming clear to me that I will not alter the input format of istream that is too much changed for pratical purpose, since file input is the major method to fetch data for a large matrix.
Under this constrain, I try to make the appearance of initializer_list as friendly as possible. I did some experiments, and found that the complex_literals expression is acceptable by initializer_list. And it looks ok to me.
using namespace std::complex_literals;
int main()
{
cMatrix cx(3,2);
cx = { { 1+2.2j , 4j}, { 5.3+6.5j , 8.3j}, {8.3, 5.6+4j} };
std::cout << cx << std::endl;
cx << " (1,2) (3,4) (5,6) (7,8) (2.3, 3.4) (2,7.8) ";
std::cout << cx << std::endl;
return 0;
}
And it works.
$ ./a.exe
(1.000000,2.200000) (0.000000,4.000000)
(5.300000,6.500000) (0.000000,8.300000)
(8.300000,0.000000) (5.600000,4.000000)
(1.000000,2.000000) (3.000000,4.000000)
(5.000000,6.000000) (7.000000,8.000000)
(2.300000,3.400000) (2.000000,7.800000)
Thank you for your patience, and please let me know if there are better ways.
I want to check whether an element exists in the vector or not. I know the below piece of code will check it.
#include <algorithm>
if ( std::find(vector.begin(), vector.end(), item) != vector.end() )
std::cout << "found";
else
std::cout << "not found";
But I have the vector of any type. i.e. std::vector<std::any>
I am pushing elements into vector like this.
std::vector<std::any> temp;
temp.emplace_back(std::string("A"));
temp.emplace_back(10);
temp.emplace_back(3.14f);
So I need to find whether string "A" present in the vector or not. Can std::find help here?
As of now I am using below piece of code to do this
bool isItemPresentInAnyVector(std::vector<std::any> items, std::any item)
{
for (const auto& it : items)
{
if (it.type() == typeid(std::string) && item.type() == typeid(std::string))
{
std::string strVecItem = std::any_cast<std::string>(it);
std::string strItem = std::any_cast<std::string>(item);
if (strVecItem.compare(strItem) == 0)
return true;
}
else if (it.type() == typeid(int) && item.type() == typeid(int))
{
int iVecItem = std::any_cast<int>(it);
int iItem = std::any_cast<int>(item);
if (iVecItem == iItem)
return true;
}
else if (it.type() == typeid(float) && item.type() == typeid(float))
{
float fVecItem = std::any_cast<float>(it);
float fItem = std::any_cast<float>(item);
if (fVecItem == fItem)
return true;
}
}
return false;
}
This should work good I guess:
#include <vector>
#include <string>
#include <any>
#include <algorithm>
#include <iostream>
int main(){
std::vector<std::any> temp;
temp.emplace_back(std::string("A"));
temp.emplace_back(10);
temp.emplace_back(3.14f);
int i = 10;//you can use any type for i variable and it should work fine
//std::string i = "A";
auto found = std::find_if(temp.begin(), temp.end(), [i](const auto &a){
return typeid(i) == a.type() && std::any_cast<decltype(i)>(a) == i;
} );
std::cout << std::any_cast<decltype(i)>(*found);
}
Or to make the code a bit more generic and reusable:
#include <vector>
#include <string>
#include <any>
#include <algorithm>
#include <iostream>
auto any_compare = [](const auto &i){
return [i] (const auto &val){
return typeid(i) == val.type() && std::any_cast<decltype(i)>(val) == i;
};
};
int main(){
std::vector<std::any> temp;
temp.emplace_back(std::string("A"));
temp.emplace_back(10);
temp.emplace_back(3.14f);
//int i = 10;
std::string i = "A";
auto found = std::find_if(temp.begin(), temp.end(), any_compare(i));
std::cout << std::any_cast<decltype(i)>(*found);
}
Live demo
Important note: this is guaranteed to work only within single translation unit due to stadard requirements on std::any type (for example same types don't need to have same type identifier in different translation units)
Using an any for this kind of purpose is not a good use of any. The best way to go is just to use a variant - since you have a closed set of types:
struct Equals {
template <typename T>
constexpr bool operator()(T const& a, T const& b) const { return a == b; }
template <typename T, typename U>
constexpr bool operator()(T const& a, U const& b) const { return false; }
};
using V = std::variant<int, float, std::string>
bool isItemPresentInAnyVector(std::vector<V> const& items, V const& item)
{
auto it = std::find_if(items.begin(), items.end(), [&](V const& elem){
return std::visit(Equals{}, elem, item);
});
return it != items.end();
}
Actually it's even better, because as Kilian points out, variant's operator== already works exactly like this:
using V = std::variant<int, float, std::string>
bool isItemPresentInAnyVector(std::vector<V> const& items, V const& item)
{
return std::find(items.begin(), items.end(), item) != items.end();
}
Unfortunately if you want to find an std::any instance in a vector of std::any instances the answer is no.
std::any does need some "magic" for example to be able to handle the creation of unknown object types but this machinery is private and must only supports object creation and not equality comparison.
It would be possible to implement what you are looking for using the same approach, but not with standard std::any that doesn't publish the needed details. The "manager" template needs to enumerate all possible operations and, for example, in g++ implementation they're "access", "get_type_info", "clone", "destroy", "xfer".
variant is completely different, because explicitly lists all the allowed types and therefore in any place it's used can access all the methods.
Comparison with typeId() should be avoided since it's dependent from translation unit.
A much safer approach can be used with any_cast of pointers:
template<typename T>
std::optional<T> find(const std::vector<std::any>& v)
{
for(auto&& e : v){
if(auto ptr = std::any_cast<T>(&e)){
return *ptr;
}
}
return std::nullopt;
}
Find first element with the given type, or nullopt if it's not found.
If we want to find all element with a specific instead:
template<typename T>
std::vector<T> findAll(const std::vector<std::any>& v)
{
std::vector<T> out;
for(auto&& e : v){
if(auto ptr = std::any_cast<T>(&e)){
out.push_back(*ptr);
}
}
return out;
}
Usage:
int main()
{
std::vector<std::any> temp;
temp.emplace_back(std::string("A"));
temp.emplace_back(10);
temp.emplace_back(3.14f);
temp.emplace_back(12);
temp.emplace_back(std::string("B"));
auto outInt = findAll<int>(temp);
std::cout << "out int: " << outInt.size() << std::endl;
for(auto&& out : outInt)
std::cout << out << std::endl;
auto outString = findAll<std::string>(temp);
std::cout << "out string: " << outString.size() << std::endl;
for(auto&& out : outString)
std::cout << out << std::endl;
auto singleInt = find<int>(temp);
if(singleInt)
std::cout << "first int " << *singleInt << std::endl;
auto singleBool = find<bool>(temp);
if(!singleBool)
std::cout << "ok: bool not found" << std::endl;
}
LIVE DEMO
If the types are int, float and string (or a limited set of types), you can use a combination of std::variant and std::get_if to achieve what you want to do in a simple manner:
std::get_if is to determine which of the types is stored in the std::variant.
A minimal example:
#include <iostream>
#include <vector>
#include <string>
#include <variant>
int main(){
std::vector<std::variant<int, float, std::string>> temp;
temp.emplace_back(std::string("A"));
temp.emplace_back(10);
temp.emplace_back(3.14f);
for (const auto& var: temp) {
if(std::get_if<std::string>(&var)) {
if(std::get<std::string>(var) == "A") std::cout << "found string\n";
}
if(std::get_if<int>(&var)) {
if(std::get<int>(var) == 10) std::cout << "found int\n";
}
if(std::get_if<float>(&var)) {
if(std::get<float>(var) == 3.14f) std::cout << "found float\n";
}
}
}
Live Demo
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 trying to print different kinds of containers with the use of operator overloading. However when I want to print a map<int, stack<vector<int > > >it returns an empty string where the stack should be.
When I try to print the stack seperately I do not have any problems.
#include <vector>
#include <stack>
#include <deque>
#include <set>
#include <iostream>
#include <map>
using namespace std;
typedef struct {
string naam;
int leeftijd;
}Persoon;
ostream& operator<<(ostream& out, const Persoon &p) {
out<<"! "<<p.naam<<" "<<p.leeftijd<<" !";
return out;
}
template<typename D, typename T>
ostream& operator<<(ostream&out, map<T,D> &m) {
typename map<T,D>::iterator my_it = m.begin();
out<<"[*] ";
while(my_it != m.end()) {
cout<<my_it->first<< " -> "<<my_it->second<<" ";
my_it++;
}
out<<"[*]\n";
}
template<typename T>
ostream& operator<<(ostream& out, vector<T> &v){
out<<"[";
int i;
for(i = 0; i < v.size()-1; i++) {
out<<v[i]<<"|";
}
out<<v[i]<<"]\n";
return out;
}
template <typename T>
ostream& operator<<(ostream& out, stack<T> &s){
out<<"{";
while(!s.empty()) {
out<<"|"<<s.top()<<"|";
s.pop();
}
out<<"}\n";
return out;
}
int main() {
vector<int> v(5,3);
/*cout<<v;
stack<string> s;
s.push("Plate1");
s.push("Plate2");
s.push("Plate3");
cout<<s;
map<int, Persoon> m;
Persoon Bill = {"Bill",59};
Persoon Steven = {"Steven",79};
Persoon Rob = {"Rob",26};
m.insert(pair<int,Persoon>(59,Bill));
m.insert(pair<int,Persoon>(79,Steven));
m.insert(pair<int,Persoon>(26,Rob));
cout<<m;
*/
stack<vector<int> > s2;
s2.push(v);
s2.push(v);
cout<<s2;
map<int, stack<vector<int> > > m2;
m2.insert(pair<int, stack<vector<int> > >(5,s2));
cout<<m2;
}
Your operator<< for stack is popping all of the elements off of the stack, so the stack is empty by the time you make a copy of it to put in the map.
To demonstrate, if I change your main() to this:
int main() {
stack<int> s2;
s2.push(1);
s2.push(2);
cout << s2.size() << '\n';
cout << s2;
cout << s2.size() << '\n';
}
The output is:
2
{|2||1|}
0
As far as I can tell, popping is the only way to "iterate" over a stack's elements (even in C++11), so you probably have no choice but to make a copy of the stack inside your operator and pop off all of the copy's elements. This code seems to work for me:
ostream& operator<<(ostream& out, stack<T> &s){
stack<T> scopy = s;
out<<"{";
while(!scopy.empty()) {
out<<"|"<<scopy.top()<<"|";
scopy.pop();
}
out<<"}\n";
return out;
}