Passing vector to a thread function in c++ - c++

I am trying to run a multi-threaded matrix sum function, so that each line will sum up in a different thread. I have tried implementing all workarounds for passing vector to a cpp thread function in a template class but I still get this common error.
For the code:
template <typename T> class Matrix
{
// variables for matrix size and variables in a one dimension vector
unsigned int _rows;
unsigned int _cols;
vector<vector<T> > _matrix;
// Matrix template class functions declarations (all common operators and constructors)
void sumLine(vector<T>& first, vector<T>& second, vector<T>& result);
Matrix<T> operator+(const Matrix<T> & other) const;
};
// Matrix template class functions implmentations
template <typename T> void Matrix<T>::sumLine(vector<T>& first, vector<T>& second, vector<T>& result)
{
for (unsigned int colIdx = 0; colIdx < _cols; colIdx++)
{
result[colIdx] = first[colIdx] + second[colIdx];
}
}
template <typename T> Matrix<T> Matrix<T>::operator+(const Matrix<T> & other) const
{
vector<thread> threads;
vector<vector<T> > results;
vector<T> newRow(_cols);
results.resize(_rows, newRow);
for (unsigned int rowIdx = 0; rowIdx < _rows; rowIdx++)
{
vector<T> first = _matrix[rowIdx];
vector<T> second = other._matrix[rowIdx];
vector<T> result = results[rowIdx];
threads.push_back(thread(Matrix<T>::sumLine, std::ref(first), std::ref(second), std::ref(result)));
}
for (unsigned int thrdIdx = 0; thrdIdx < _rows; thrdIdx++)
{
threads[thrdIdx].join();
}
// do something with vector<vector<T>> results
}
and still after compiling with gcc I get:
In file included from /usr/lib/gcc/x86_64-pc-cygwin/4.9.3/include/c++/thread:39:0,
from Matrix.hpp:12,
from main.cpp:13:
/usr/lib/gcc/x86_64-pc-cygwin/4.9.3/include/c++/functional: In instantiation of 'struct std::_Bind_simple<std::_Mem_fn<void (Matrix<Complex>::*)(std::vector<Complex, std::allocator<Complex> >&, std::vector<Complex, std::allocator<Complex> >&, std::vector<Complex, std::allocator<Complex> >&)>(std::reference_wrapper<std::vector<Complex, std::allocator<Complex> > >, std::reference_wrapper<std::vector<Complex, std::allocator<Complex> > >, std::reference_wrapper<std::vector<Complex, std::allocator<Complex> > >)>':
/usr/lib/gcc/x86_64-pc-cygwin/4.9.3/include/c++/thread:137:47: required from 'std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (Matrix<Complex>::*)(std::vector<Complex, std::allocator<Complex> >&, std::vector<Complex, std::allocator<Complex> >&, std::vector<Complex, std::allocator<Complex> >&); _Args = {std::reference_wrapper<std::vector<Complex, std::allocator<Complex> > >, std::reference_wrapper<std::vector<Complex, std::allocator<Complex> > >, std::reference_wrapper<std::vector<Complex, std::allocator<Complex> > >}]'
Matrix.hpp:404:102: required from 'Matrix<T> Matrix<T>::operator+(const Matrix<T>&) const [with T = Complex]'
main.cpp:59:14: required from here
/usr/lib/gcc/x86_64-pc-cygwin/4.9.3/include/c++/functional:1665:61: error: no type named 'type' in 'class std::result_of<std::_Mem_fn<void (Matrix<Complex>::*)(std::vector<Complex, std::allocator<Complex> >&, std::vector<Complex, std::allocator<Complex> >&, std::vector<Complex, std::allocator<Complex> >&)>(std::reference_wrapper<std::vector<Complex, std::allocator<Complex> > >, std::reference_wrapper<std::vector<Complex, std::allocator<Complex> > >, std::reference_wrapper<std::vector<Complex, std::allocator<Complex> > >)>'
typedef typename result_of<_Callable(_Args...)>::type result_type;
^
/usr/lib/gcc/x86_64-pc-cygwin/4.9.3/include/c++/functional:1695:9: error: no type named 'type' in 'class std::result_of<std::_Mem_fn<void (Matrix<Complex>::*)(std::vector<Complex, std::allocator<Complex> >&, std::vector<Complex, std::allocator<Complex> >&, std::vector<Complex, std::allocator<Complex> >&)>(std::reference_wrapper<std::vector<Complex, std::allocator<Complex> > >, std::reference_wrapper<std::vector<Complex, std::allocator<Complex> > >, std::reference_wrapper<std::vector<Complex, std::allocator<Complex> > >)>'
_M_invoke(_Index_tuple<_Indices...>)
When Complex is a complex number class I wrote for the matrix template class, and my main function is trying to use this calculation with it. What is wrong here? If it is in the complex class, is there a simpler way to pass the parameters to the thread function to avoid this?

you should post your Complex class, it may be the problem.
also in your code:
vector<T> first = _matrix[rowIdx];
vector<T> second = other._matrix[rowIdx];
vector<T> result = results[rowIdx];
you should write it like this: vector<T>& first = _matrix[rowIdx];
because you are copying those vectors... or even const vector<T>& first = _matrix[rowIdx]; if you don't modify them.
then you can remove the std::ref

the following code compiles (with clang 3.5) and avoids passing references to temporaries to any thread ...
#include <vector>
#include <thread>
#include <stdexcept>
using namespace std; // for expose only (don't do this in real code!!)
template <typename T> class Matrix
{
using row = vector<T>;
size_t _rows, _cols;
vector<row> _matrix;
Matrix(vector<row>&&); // defined elsewhere
row sumLine(row const& first, row const& second) const
{
row result; // don't tempt the compiler to default
result.reserve(_cols); // initialise result[i] for all columns
for(size_t c=0; c!=_cols; ++c)
result.emplace_back(first[c]+second[c]);
return result; // return is fast (no copy!)
}
Matrix<T> operator+ (const Matrix<T>& other) const;
};
template <typename T>
Matrix<T> Matrix<T>::operator+(const Matrix<T>&other) const
{
if(other._cols != _cols)
throw std::runtime_error("column number mismatch in Matrix+Matrix");
if(other._rows != _rows)
throw std::runtime_error("row number mismatch in Matrix+Matrix");
vector<thread> threads; threads.reserve(_rows);
vector<row> result(_rows);
for(size_t r=0; r!=_rows; ++r)
threads.emplace_back([&,r]() {
result[r] = Matrix<T>::sumLine(_matrix[r],other._matrix[r]);
});
for(size_t r=0; r!=_rows; ++r)
threads[r].join();
return move(result);
}
template class Matrix<double>;

Related

c++ - copy constructor for template class

My class is a matrix composed out of vectors of vectors, and I seem to have problems in my constructor:
#include <vector>
#include <exception>
#include <iostream>
using namespace std;
template<class T>
class Matrix
{
private:
unsigned int _rows;
unsigned int _cols;
vector <vector<T>> _matrix;
public:
const unsigned int INITIAL_ROW_SIZE = 1;
const unsigned int INITIAL_COL_SIZE = 1;
Matrix () : _rows(INITIAL_COL_SIZE), _cols(INITIAL_COL_SIZE),
_matrix(1,vector<T>(1)) {
cout << "ctor" << endl;
}
Matrix (unsigned int rows, unsigned int cols) : _rows(rows), _cols(cols),_matrix(_rows,vector<T>(_cols) {
}
Matrix (const Matrix<T> &other) :Matrix(other._rows, other._cols)
{
for(int i = 0; i < _rows; i++)
{
copy(other._matrix[i].begin(), other._matrix[i].end(), _matrix[i]);
}
};
}
the code will not compile when i try to use the copy constructor,
as in Matric<int> m(5,5); Matrix<int> n=(m); because:
In file included from /usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/vector:60:0,
from /cppex3/ex3/Matrix.hpp:8,
from /cppex3/ex3/Tester.cpp:6:
/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/bits/stl_algobase.h: In instantiation of '_OI std::__copy_move_a(_II, _II, _OI) [with bool _IsMove = false; _II = const std::vector<int, std::allocator<int> >*; _OI = std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >]':
/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/bits/stl_algobase.h:438:45: required from '_OI std::__copy_move_a2(_II, _II, _OI) [with bool _IsMove = false; _II = __gnu_cxx::__normal_iterator<const std::vector<int, std::allocator<int> >*, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > >; _OI = std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >]'
/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/bits/stl_algobase.h:471:8: required from '_OI std::copy(_II, _II, _OI) [with _II = __gnu_cxx::__normal_iterator<const std::vector<int, std::allocator<int> >*, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > >; _OI = std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >]'
/ex3/Matrix.hpp:42:13: required from 'Matrix<T>::Matrix(const Matrix<T>&) [with T = int]'
/ex3/Tester.cpp:25:20: required from here
/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/bits/stl_algobase.h:394:57: error: no type named 'value_type' in '[01mstruct std::iterator_traits<std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > >'
typedef typename iterator_traits<_OI>::value_type _ValueTypeO;
^
/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/bits/stl_algobase.h:399:9: error: no type named 'value_type' in 'struct std::iterator_traits<std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > >'
&& __are_same<_ValueTypeI, _ValueTypeO>::__value);
^
I suspect my initalization of the _matrix member is not correct, but I'm not sure. it could also by std::copy but the syntax seems correct.
Try with
copy(other._matrix[i].begin(), other._matrix[i].end(),
std::back_inserter(_matrix[i]));
or with
Matrix (const Matrix<T> &other)
: _rows{other._rows}, _cols{other._cols}, _matrix{other._matrix}
{
}
Try this code, it works
Replace your
copy(other._matrix[i].begin(), other._matrix[i].end(), _matrix[i]);
with
copy(other._matrix[i].begin(), other._matrix[i].end(), _matrix[i].begin());
Below is the complete code.
#include <vector>
#include <exception>
#include <iostream>
using namespace std;
template<class T>
class Matrix
{
private:
unsigned int _rows;
unsigned int _cols;
vector <vector<T> > _matrix;
public:
Matrix () : _rows(1), _cols(1),
_matrix(1,vector<T>(1))
{
cout << "ctor" << endl;
}
Matrix (unsigned int rows, unsigned int cols) : _rows(rows), _cols(cols)
{
_matrix=vector< vector<T> >(rows,vector<T>(cols));
}
Matrix (const Matrix<T> &other)
: _rows{other._rows}, _cols{other._cols}, _matrix{other._matrix}
{
for(int i = 0; i < _rows; i++)
{
std::copy(other._matrix[i].begin(), other._matrix[i].end(), _matrix[i].begin());
}
}
};
int main(int argc, char const *argv[])
{
Matrix<int> m(5,5);
Matrix<int> n1(m);
Matrix<int> n2(m);
return 0;
}
Also
Matrix (const Matrix<T> &other) :Matrix(other._rows, other._cols);
replaced it with
Matrix (const Matrix<T> &other) {
Matrix(other._rows, other._cols);
...

error: no type named 'type' while calling static function from a thread

Inside my generic Matrix(T) class I'm overloading operator+ using threading using a static function that adds to a single row like this:
template <class T>
static void addToRow(vector<T> &dest, const vector<T> &source, int pos, int colls)
{
typename vector<T>::iterator itDest = dest.begin() + pos;
typename vector<T>::iterator itSource = source.cend() + pos;
int counter = 0;
while (counter != colls)
{
*itDest++ += *itSource++;
++counter;
}
}
this function is implemented outside the class.
inside the operator+ overload I'm trying to call it like this:
const Matrix<T> operator+(const Matrix<T> &other) const
{
Matrix<T> result(*this);
vector<std::thread> threads;
int i, pos;
std::thread thrd;
for (i = 0; i < _rows; ++i)
{
pos = i*_colls;
threads.push_back(std::thread(&addToRow<T>, ref(_matrix), cref(other._matrix), pos, _colls));
}
typename vector<std::thread>::iterator it;
for (it = threads.begin(); it != threads.end(); ++it)
{
it->join();
}
return result;
}
and for the line:
threads.push_back(std::thread(&addToRow<T>, std::ref(*this), _matrix, other._matrix, pos, _colls));
I get the error:
/cygdrive/c/Users/Roy/Desktop/semester s year 1/CPP/ex3/Matrix.hpp:201:102: required from 'const Matrix<T> Matrix<T>::operator+(const Matrix<T>&) const [with T = int]'
/cygdrive/c/Users/Roy/Desktop/semester s year 1/CPP/ex3/main.cpp:44:31: required from here
/usr/lib/gcc/x86_64-pc-cygwin/4.9.3/include/c++/functional:1665:61: error: no type named 'type' in 'class std::result_of<void (*(const Matrix<int>*, std::vector<int, std::allocator<int> >, std::vector<int, std::allocator<int> >, int, int))(std::vector<int, std::allocator<int> >&, const std::vector<int, std::allocator<int> >&, int)>'
typedef typename result_of<_Callable(_Args...)>::type result_type;

C++: Help Creating unordered_map with User-Defined Hash/Equality

I'm trying to create a std::unordered_map, using a user-defined hash function and equality predicate, for matrix rows of integral built-in types. I use std::bind, since I need the hashing and equality functors to work for variable ranges. How would I get the following code to compile and work as intended? I'm guessing that my mistake is towards the bottom of the listing, where I use std::bind and instantiate the std::unordered_map.
Some clarifications:
I can't use boost::hash_combine because I care about individual bits in the integers stored in the matrix row, so unless I create my own iterator, boost::hash_combine would combine whole integers, leading to erroneous results. Also, I need the hash and equality functors to work on ranges from 1 to ~200,000, so specifying the range in template parameters would not be a reasonable option.
template <class T,class F,class A>
struct row_hash_right : std::function<size_t(
ublas::matrix_row<ublas::matrix<T,F,A>>,
unsigned, unsigned)>
{
typedef ublas::matrix_row<ublas::matrix<T,F,A>> row_type;
// I want to use std::bind to bind the last two arguments.
size_t operator()(row_type& a, unsigned s, unsigned e)
{
// Implementation of hash function.
}
};
template <class T,class F,class A>
struct row_equal_right : std::function<bool(
ublas::matrix_row<ublas::matrix<T,F,A>>,
ublas::matrix_row<ublas::matrix<T,F,A>>,
unsigned, unsigned)>
{
typedef ublas::matrix_row<ublas::matrix<T,F,A>> row_type;
bool operator()(row_type& a, row_type& b, unsigned s, unsigned e)
{
// Implementation of equality predicate.
}
};
// Inside a function.
for (unsigned i = 0; i < len; ++i) {
for (unsigned j = i + 1; j < len; ++j) {
auto x = std::bind(r_hash, _1, i, j);
auto y = std::bind(r_equal, _1, _2, i, j);
// ERROR:
std::unordered_map<row_type, unsigned,
decltype(x), decltype(y)> m(256, x, y);
}
}
The error:
Here is (what I think) the most important part of the error produced upon attempted compilation:
/usr/include/c++/4.6/bits/stl_pair.h:92:11: error: ‘std::pair<_T1,
_T2>::first’ has incomplete type
/usr/include/boost/numeric/ublas/fwd.hpp:73:11: error: declaration of ‘const struct
boost::numeric::ublas::matrix_row,
boost::numeric::ublas::unbounded_array > > >’
If you want the see the whole thing, I've dumped it all here:
In file included from /usr/include/c++/4.6/bits/stl_algobase.h:65:0,
from /usr/include/c++/4.6/bits/char_traits.h:41,
from /usr/include/c++/4.6/ios:41,
from /usr/include/c++/4.6/ostream:40,
from /usr/include/c++/4.6/iostream:40,
from src/test/read_test.cpp:1:
/usr/include/c++/4.6/bits/stl_pair.h: In instantiation of ‘std::pair, boost::numeric::ublas::unbounded_array > > >, unsigned int>’:
/usr/include/c++/4.6/bits/stl_function.h:486:12: instantiated from ‘std::_Select1st, boost::numeric::ublas::unbounded_array > > >, unsigned int> >’
/usr/include/c++/4.6/bits/hashtable_policy.h:789:20: instantiated from ‘std::__detail::_Hash_code_base, boost::numeric::ublas::unbounded_array > > >, std::pair, boost::numeric::ublas::unbounded_array > > >, unsigned int>, std::_Select1st, boost::numeric::ublas::unbounded_array > > >, unsigned int> >, std::_Bind, boost::numeric::ublas::unbounded_array > >(std::_Placeholder, std::_Placeholder, unsigned int, unsigned int)>, std::_Bind, boost::numeric::ublas::unbounded_array > >(std::_Placeholder, unsigned int, unsigned int)>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, false>’
/usr/include/c++/4.6/bits/hashtable.h:105:11: instantiated from ‘std::_Hashtable, boost::numeric::ublas::unbounded_array > > >, std::pair, boost::numeric::ublas::unbounded_array > > >, unsigned int>, std::allocator, boost::numeric::ublas::unbounded_array > > >, unsigned int> >, std::_Select1st, boost::numeric::ublas::unbounded_array > > >, unsigned int> >, std::_Bind, boost::numeric::ublas::unbounded_array > >(std::_Placeholder, std::_Placeholder, unsigned int, unsigned int)>, std::_Bind, boost::numeric::ublas::unbounded_array > >(std::_Placeholder, unsigned int, unsigned int)>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, false, false, true>’
/usr/include/c++/4.6/bits/unordered_map.h:44:11: instantiated from ‘std::__unordered_map, boost::numeric::ublas::unbounded_array > > >, unsigned int, std::_Bind, boost::numeric::ublas::unbounded_array > >(std::_Placeholder, unsigned int, unsigned int)>, std::_Bind, boost::numeric::ublas::unbounded_array > >(std::_Placeholder, std::_Placeholder, unsigned int, unsigned int)>, std::allocator, boost::numeric::ublas::unbounded_array > > >, unsigned int> >, false>’
/usr/include/c++/4.6/bits/unordered_map.h:256:11: instantiated from ‘std::unordered_map, boost::numeric::ublas::unbounded_array > > >, unsigned int, std::_Bind, boost::numeric::ublas::unbounded_array > >(std::_Placeholder, unsigned int, unsigned int)>, std::_Bind, boost::numeric::ublas::unbounded_array > >(std::_Placeholder, std::_Placeholder, unsigned int, unsigned int)>, std::allocator, boost::numeric::ublas::unbounded_array > > >, unsigned int> > >’
./sal/alg/ehh.hpp:144:31: instantiated from ‘sal::ehh_results sal::compute_ehh(boost::numeric::ublas::matrix&, unsigned int) [with FloatType = double, T = unsigned int, F = boost::numeric::ublas::basic_row_major, A = boost::numeric::ublas::unbounded_array >]’
src/test/read_test.cpp:11:51: instantiated from here
/usr/include/c++/4.6/bits/stl_pair.h:92:11: error: ‘std::pair::first’ has incomplete type
/usr/include/boost/numeric/ublas/fwd.hpp:73:11: error: declaration of ‘const struct boost::numeric::ublas::matrix_row, boost::numeric::ublas::unbounded_array > > >’
If you want to hash a range of things, you need something like hash_combine(). I usually lift this function from Boost (surprisingly, it wasn't included in the standard!). Here's how I'd use it on std::arrays, and I trust you can manipulate this into something to work on matrix rows:
#include <array>
template <class T>
inline void hash_combine(std::size_t & seed, const T & v)
{
std::hash<T> hasher;
seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
namespace std
{
template<typename T, size_t N> struct hash<array<T, N>>
{
inline size_t operator()(const array<T, N> & a) const
{
size_t seed = 0;
for (size_t i = 0; i != N; ++i)
{
::hash_combine(seed, a[i]);
}
return seed;
}
};
}
(The above specialisation allows you to use std::unordered_set<std::array<int, 10>> etc.)
If the matrix rows don't come with an equality predicate, you could also add a specialization of std::equal_to for matrix rows.

What is wrong with this template code?

#include <iostream>
#include <map>
#include <vector>
template<typename T>
class foo {
public:
foo(T val) : m_Value(val) { };
T get_value() const { return m_Value; };
void set_value(const T& t) { m_Value=t; };
bool operator<(const foo<T>& x) { return x.get_value() < m_Value; };
bool operator==(const foo<T>& x) { return x.get_value() == m_Value; };
private:
T m_Value;
};
template<typename T>
class bar {
public:
bar() { };
void print_first() const {
typename std::map<foo<T>,std::vector<foo<T> > >::iterator it;
it = m_Map.begin(); //ERROR!
std::cout << it->first.get_value() << std::endl;
};
private:
std::map<foo<T>,std::vector<foo<T> > > m_Map;
};
int main() {
bar<int> b;
b.print_first();
return 0;
};
I am trying to write a container, but the member functions require use of an iterator, but when I try to actually use an iterator, I get an error:
testcase.cpp: In member function `void bar<T>::print_first() const [with T =
int]':
testcase.cpp:33: instantiated from here
testcase.cpp:24: error: no match for 'operator=' in 'it = std::map<_Key, _Tp,
_Compare, _Alloc>::begin() const [with _Key = foo<int>, _Tp =
std::vector<foo<int>, std::allocator<foo<int> > >, _Compare =
std::less<foo<int> >, _Alloc = std::allocator<std::pair<const foo<int>,
std::vector<foo<int>, std::allocator<foo<int> > > > >]()'
/usr/include/c++/3.3.3/bits/stl_tree.h:184: error: candidates are:
std::_Rb_tree_iterator<std::pair<const foo<int>, std::vector<foo<int>,
std::allocator<foo<int> > > >, std::pair<const foo<int>,
std::vector<foo<int>, std::allocator<foo<int> > > >&, std::pair<const
foo<int>, std::vector<foo<int>, std::allocator<foo<int> > > >*>&
std::_Rb_tree_iterator<std::pair<const foo<int>, std::vector<foo<int>,
std::allocator<foo<int> > > >, std::pair<const foo<int>,
std::vector<foo<int>, std::allocator<foo<int> > > >&, std::pair<const
foo<int>, std::vector<foo<int>, std::allocator<foo<int> > >
>*>::operator=(const std::_Rb_tree_iterator<std::pair<const foo<int>,
std::vector<foo<int>, std::allocator<foo<int> > > >, std::pair<const
foo<int>, std::vector<foo<int>, std::allocator<foo<int> > > >&,
std::pair<const foo<int>, std::vector<foo<int>, std::allocator<foo<int> > >
>*>&)
What is it that i'm doing wrong?
Thanks in advance.
print_first is a const method. Therefore the member m_Map is also const, and its begin method doesn't return an ordinary iterator, but a const_iterator. Change
typename std::map<foo<T>,std::vector<foo<T> > >::iterator it;
to
typename std::map<foo<T>,std::vector<foo<T> > >::const_iterator it;
and you should be good to go.

Why doesn't my custom iterator work with the STL copy?

I wrote an OutputIterator for an answer to another question. Here it is:
#include <queue>
using namespace std;
template< typename T, typename U >
class queue_inserter {
queue<T, U> &qu;
public:
queue_inserter(queue<T,U> &q) : qu(q) { }
queue_inserter<T,U> operator ++ (int) { return *this; }
queue_inserter<T,U> operator * () { return *this; }
void operator = (const T &val) { qu.push(val); }
};
template< typename T, typename U >
queue_inserter<T,U> make_queue_inserter(queue<T,U> &q) {
return queue_inserter<T,U>(q);
}
This works great for this little copy function:
template<typename II, typename OI>
void mycopy(II b, II e, OI oi) {
while (b != e) { *oi++ = *b++; }
}
But it doesn't work at all for the STL copy from algorithms. Here are the wonderful C++ errors I get:
i.cpp:33: error: specialization of ‘template<class _Iterator> struct std::iterator_traits’ in different namespace
/usr/include/c++/4.0.0/bits/stl_iterator_base_types.h:127: error: from definition of ‘template<class _Iterator> struct std::iterator_traits’
/usr/include/c++/4.0.0/bits/stl_algobase.h: In function ‘_OI std::__copy_aux(_II, _II, _OI) [with _II = int*, _OI = queue_inserter<int, std::deque<int, std::allocator<int> > >]’:
/usr/include/c++/4.0.0/bits/stl_algobase.h:335: instantiated from ‘static _OI std::__copy_normal<true, false>::copy_n(_II, _II, _OI) [with _II = __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, _OI = queue_inserter<int, std::deque<int, std::allocator<int> > >]’
/usr/include/c++/4.0.0/bits/stl_algobase.h:387: instantiated from ‘_OutputIterator std::copy(_InputIterator, _InputIterator, _OutputIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, _OutputIterator = queue_inserter<int, std::deque<int, std::allocator<int> > >]’
i.cpp:53: instantiated from here
/usr/include/c++/4.0.0/bits/stl_algobase.h:310: error: no type named ‘value_type’ in ‘struct std::iterator_traits<queue_inserter<int, std::deque<int, std::allocator<int> > > >’
/usr/include/c++/4.0.0/bits/stl_algobase.h:315: error: no type named ‘value_type’ in ‘struct std::iterator_traits<queue_inserter<int, std::deque<int, std::allocator<int> > > >’
/usr/include/c++/4.0.0/bits/stl_algobase.h:315: error: ‘__value’ is not a member of ‘<declaration error>’
/usr/include/c++/4.0.0/bits/stl_algobase.h:335: instantiated from ‘static _OI std::__copy_normal<true, false>::copy_n(_II, _II, _OI) [with _II = __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, _OI = queue_inserter<int, std::deque<int, std::allocator<int> > >]’
/usr/include/c++/4.0.0/bits/stl_algobase.h:387: instantiated from ‘_OutputIterator std::copy(_InputIterator, _InputIterator, _OutputIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, _OutputIterator = queue_inserter<int, std::deque<int, std::allocator<int> > >]’
i.cpp:53: instantiated from here
/usr/include/c++/4.0.0/bits/stl_algobase.h:317: error: ‘__simple’ is not a valid template argument for type ‘bool’ because it is a non-constant expression
/usr/include/c++/4.0.0/bits/stl_algobase.h:317: error: ‘copy’ is not a member of ‘<declaration error>’
Here is the driver:
int main() {
vector<int> v;
v.push_back( 1 );
v.push_back( 2 );
queue<int> q;
copy( v.begin(), v.end(), make_queue_inserter(q) );
while (q.size() > 0) {
cout << q.front() << endl;
q.pop();
}
}
Why in the world is it specializing iterator_traits. What's wrong with my iterator? Can't I just write my own simple iterators?
Your queue_inserter needs to be derived from std::iterator so that all the typedefs such as value_type are properly defined since these are used inside STL algorithms This definition works:
template< typename T, typename U >
class queue_inserter : public std::iterator<std::output_iterator_tag, T>{
queue<T, U> &qu;
public:
queue_inserter(queue<T,U> &q) : qu(q) { }
queue_inserter<T,U> operator ++ (int) { return *this; }
queue_inserter<T,U> operator ++ () { return *this; }
queue_inserter<T,U> operator * () { return *this; }
void operator = (const T &val) { qu.push(val); }
};
Derive it from std::iterator. If you are interested the Dr. Dobb's has an article about custom containers and iterators.
Your iterator doesn't meet the requirement for an 'assignable' type which is a requirement for an output iterator because it contains a reference and assignable types need to ensure that after t = u that t is equivalent to u.
You can provide a suitable specialization for iterator_traits for your iterator either by deriving from a specialization of std::iterator or by providing one explicitly.
namespace std
{
template<> struct iterator_traits<MyIterator>
{
typedef std::output_iterator_tag iterator_category;
typedef void value_type;
typedef void difference_type;
};
}
#include <queue>
#include <algorithm>
#include <iterator>
#include <iostream>
using namespace std;
template< typename T, typename U >
class queue_inserter
{
queue<T, U> &qu;
public:
// for iterator_traits to refer
typedef output_iterator_tag iterator_category;
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef T& reference;
queue_inserter(queue<T,U> &q) : qu(q) { }
queue_inserter<T,U>& operator ++ () { return *this; }
queue_inserter<T,U> operator * () { return *this; }
void operator = (const T &val) { qu.push(val); }
};
template< typename T, typename U >
queue_inserter<T,U> make_queue_inserter(queue<T,U> &q)
{
return queue_inserter<T,U>(q);
}
int main()
{
// uses initalizer list (C++0x), pass -std=c++0x to g++
vector<int> v({1, 2, 3});
queue<int, deque<int>> q;
copy(v.cbegin(), v.cend(), make_queue_inserter(q));
while (!q.empty())
{
cout << q.front() << endl;
q.pop();
}
}
This should do it with iterator_traits; a helper struct in <iterator> which defines all types an iterator should typically define. Functions in <algorithm>, refer to these types when required like iterator_traits<it>::iterator_category or say iterator_traits<it>::value_type, etc. Just defining them inside one's custom iterator would do the trick. This is the modern way of writing iterators, as opposed to the classical way of inheriting from std::iterator. Having a look at <iterator> reveals that even std::iterator defines these types i.e. iterator_category, difference_type, etc. This is the reason, when inherited from std::iterator, the derived iterator class gets these due to heredity.