Related
For this implementation of selection sort:
template <typename Iterator, typename Compare>
void sort(Iterator begin, Iterator end, Compare comp) {
for (auto i = begin; i != end; ++i) {
auto min = i;
for (auto j = i + 1; j != end; ++j) {
if (comp(*j, *min)) {
min = j;
}
}
std::swap(*min, *i);
}
}
How should I modify it so that Compare comp should be std::less method if last parameter is skipped for sort method?
I tried function overloading by introducing another method:
template <typename Iterator>
void sort(Iterator begin, Iterator end) {
sort(begin, end, std::less<std::iterator_traits<Iterator>::value_type>());
}
But it gave errors like:
In file included from ../src/selection_sort_demo.cpp:1:
../include/selection_sort.hpp:24:29: error: template argument for template type parameter must be a type; did you forget 'typename'?
sort(begin, end, std::less<std::iterator_traits<Iterator>::value_type>());
^
typename
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/6.3.1/../../../../include/c++/6.3.1/bits/stl_function.h:380:21: note: template parameter is declared here
template<typename _Tp>
^
In file included from ../src/selection_sort_demo.cpp:1:
../include/selection_sort.hpp:24:2: error: call to 'sort' is ambiguous
sort(begin, end, std::less<std::iterator_traits<Iterator>::value_type>());
^~~~
../src/selection_sort_demo.cpp:22:13: note: in instantiation of function template specialization 'selection::sort<__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > > >' requested here
selection::sort(v.begin(), v.end());
^
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/6.3.1/../../../../include/c++/6.3.1/bits/stl_algo.h:4727:5: note: candidate function [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > >, _Compare = std::less<int>]
sort(_RandomAccessIterator __first, _RandomAccessIterator __last,
^
../include/selection_sort.hpp:7:6: note: candidate function [with Iterator = __gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > >, Compare = std::less<int>]
void sort(Iterator begin, Iterator end, Compare comp)
^
2 errors generated.
[2/4] Compiling cpp object 'test/testexe#exe/selection_sort_test.cpp.o'
FAILED: test/testexe#exe/selection_sort_test.cpp.o
clang++ '-Itest/testexe#exe' '-Itest' '-I../test' '-I../include' '-Wall' '-Winvalid-pch' '-Wnon-virtual-dtor' '-std=c++14' '-O0' '-g' '-pthread' '-MMD' '-MQ' 'test/testexe#exe/selection_sort_test.cpp.o' '-MF' 'test/testexe#exe/selection_sort_test.cpp.o.d' -o 'test/testexe#exe/selection_sort_test.cpp.o' -c ../test/selection_sort_test.cpp
In file included from ../test/selection_sort_test.cpp:2:
../include/selection_sort.hpp:24:29: error: template argument for template type parameter must be a type; did you forget 'typename'?
sort(begin, end, std::less<std::iterator_traits<Iterator>::value_type>());
^
typename
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/6.3.1/../../../../include/c++/6.3.1/bits/stl_function.h:380:21: note: template parameter is declared here
template<typename _Tp>
^
In file included from ../test/selection_sort_test.cpp:2:
../include/selection_sort.hpp:24:2: error: call to 'sort' is ambiguous
sort(begin, end, std::less<std::iterator_traits<Iterator>::value_type>());
^~~~
../test/selection_sort_test.cpp:17:13: note: in instantiation of function template specialization 'selection::sort<__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > > >' requested here
selection::sort(v1.begin(), v1.end());
^
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/6.3.1/../../../../include/c++/6.3.1/bits/stl_algo.h:4727:5: note: candidate function [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > >, _Compare = std::less<int>]
sort(_RandomAccessIterator __first, _RandomAccessIterator __last,
^
../include/selection_sort.hpp:7:6: note: candidate function [with Iterator = __gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > >, Compare = std::less<int>]
void sort(Iterator begin, Iterator end, Compare comp)
^
2 errors generated.
Since it's c++14:
template <typename Iterator, typename Compare = std::less<> >
void sort(Iterator begin, Iterator end, Compare comp = Compare())
{
for (auto i = begin; i != end; ++i) {
auto min = i;
for (auto j = i + 1; j != end; ++j) {
if (comp(*j, *min)) {
min = j;
}
}
std::swap(*min, *i);
}
}
c++11:
template <typename Iterator, typename Compare = std::less< typename std::iterator_traits<Iterator>::value_type > >
void sort(Iterator begin, Iterator end, Compare comp = Compare())
{
for (auto i = begin; i != end; ++i) {
auto min = i;
for (auto j = i + 1; j != end; ++j) {
if (comp(*j, *min)) {
min = j;
}
}
std::swap(*min, *i);
}
}
Explanation:
We have to offer the compiler both a default type in the template argument list and a default function argument list.
For explanation of std::less<> since c++14 see:
http://en.cppreference.com/w/cpp/utility/functional/less
You were right, but forgot the typename keyword. Check this:
template <typename Iterator>
void sort(Iterator begin, Iterator end) {
sort(begin, end, std::less<typename std::iterator_traits<Iterator>::value_type>());
}
Probably you wanted default template argument, but this works too.
Problem
Having an adjacency list graph, I would like to traverse it with a DFS algorithm from a specific set of source nodes. The main problem is that the color map is passed by value.
I tried
To encapsulate the color map by reference into a structure :
class ref_color_map_wrapper
{
public:
typedef boost::default_color_type color_type;
typedef std::vector<color_type> color_map_type;
private:
color_map_type &color_map;
public:
ref_color_map_wrapper(color_map_type& color_map)
: color_map(color_map)
{}
color_type& operator[](size_t i)
{
return color_map[i];
}
const color_type& operator[](size_t i) const
{
return color_map[i];
}
};
namespace boost
{
template <>
struct property_traits<ref_color_map_wrapper>
{
typedef boost::read_write_property_map_tag category;
typedef boost::default_color_type value_type;
typedef boost::default_color_type& reference;
typedef size_t key_type;
};
void put(ref_color_map_wrapper& color_map, vertex_descriptor& v, boost::default_color_type color)
{
color_map[v] = color;
}
boost::default_color_type get(ref_color_map_wrapper& color_map, vertex_descriptor& v)
{
return color_map[v];
}
void put(ref_color_map_wrapper& color_map, const vertex_descriptor& v, boost::default_color_type color)
{
color_map[v] = color;
}
boost::default_color_type get(const ref_color_map_wrapper& color_map, const vertex_descriptor& v)
{
return color_map[v];
}
}
And finally the code of the DFS :
typedef std::vector<boost::default_color_type> color_map_type;
color_map_type color_map(boost::num_vertices(graph), boost::white_color);
ref_color_map_wrapper ref_color_map(color_map);
for(auto it = root_set.begin(); it != root_set.end(); ++it)
{
size_t i = boost::get(boost::vertex_index_t(), graph, *it);
if(color_map[i] == boost::white_color)
{
boost::depth_first_visit(graph, *it, boost::default_dfs_visitor(), ref_color_map);
}
}
Compilation error
/usr/local/include/boost/property_map/property_map.hpp: In instantiation of ‘void boost::ReadablePropertyMapConcept<PMap, Key>::constraints() [with PMap = gc::ref_color_map_wrapper; Key = long unsigned int]’:
/usr/local/include/boost/concept/detail/has_constraints.hpp:32:14: required by substitution of ‘template<class Model> boost::concepts::detail::yes boost::concepts::detail::has_constraints_(Model*, boost::concepts::detail::wrap_constraints<Model, (& Model:: constraints)>*) [with Model = boost::ReadablePropertyMapConcept<gc::ref_color_map_wrapper, long unsigned int>]’
/usr/local/include/boost/concept/detail/has_constraints.hpp:42:5: required from ‘const bool boost::concepts::not_satisfied<boost::ReadablePropertyMapConcept<gc::ref_color_map_wrapper, long unsigned int> >::value’
/usr/local/include/boost/concept/detail/has_constraints.hpp:45:31: required from ‘struct boost::concepts::not_satisfied<boost::ReadablePropertyMapConcept<gc::ref_color_map_wrapper, long unsigned int> >’
/usr/local/include/boost/mpl/if.hpp:67:11: required from ‘struct boost::mpl::if_<boost::concepts::not_satisfied<boost::ReadablePropertyMapConcept<gc::ref_color_map_wrapper, long unsigned int> >, boost::concepts::constraint<boost::ReadablePropertyMapConcept<gc::ref_color_map_wrapper, long unsigned int> >, boost::concepts::requirement<boost::concepts::failed************ boost::ReadablePropertyMapConcept<gc::ref_color_map_wrapper, long unsigned int>::************> >’
/usr/local/include/boost/concept/detail/general.hpp:50:8: required from ‘struct boost::concepts::requirement_<void (*)(boost::ReadablePropertyMapConcept<gc::ref_color_map_wrapper, long unsigned int>)>’
/usr/local/include/boost/concept_check.hpp:45:1: [ skipping 4 instantiation contexts ]
/usr/local/include/boost/concept/detail/has_constraints.hpp:45:31: required from ‘struct boost::concepts::not_satisfied<boost::ReadWritePropertyMapConcept<gc::ref_color_map_wrapper, long unsigned int> >’
/usr/local/include/boost/mpl/if.hpp:67:11: required from ‘struct boost::mpl::if_<boost::concepts::not_satisfied<boost::ReadWritePropertyMapConcept<gc::ref_color_map_wrapper, long unsigned int> >, boost::concepts::constraint<boost::ReadWritePropertyMapConcept<gc::ref_color_map_wrapper, long unsigned int> >, boost::concepts::requirement<boost::concepts::failed************ boost::ReadWritePropertyMapConcept<gc::ref_color_map_wrapper, long unsigned int>::************> >’
/usr/local/include/boost/concept/detail/general.hpp:50:8: required from ‘struct boost::concepts::requirement_<void (*)(boost::ReadWritePropertyMapConcept<gc::ref_color_map_wrapper, long unsigned int>)>’
/usr/local/include/boost/graph/depth_first_search.hpp:88:1: required from ‘void boost::detail::depth_first_visit_impl(const IncidenceGraph&, typename boost::graph_traits<Graph>::vertex_descriptor, DFSVisitor&, ColorMap, TerminatorFunc) [with IncidenceGraph = boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS, boost::variant<const void*, std::pair<void*, void*> > >; DFSVisitor = boost::dfs_visitor<>; ColorMap = gc::ref_color_map_wrapper; TerminatorFunc = boost::detail::nontruth2; typename boost::graph_traits<Graph>::vertex_descriptor = long unsigned int]’
/usr/local/include/boost/graph/depth_first_search.hpp:314:5: required from ‘void boost::depth_first_visit(const IncidenceGraph&, typename boost::graph_traits<Graph>::vertex_descriptor, DFSVisitor, ColorMap) [with IncidenceGraph = boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS, boost::variant<const void*, std::pair<void*, void*> > >; DFSVisitor = boost::dfs_visitor<>; ColorMap = gc::ref_color_map_wrapper; typename boost::graph_traits<Graph>::vertex_descriptor = long unsigned int]’
../include/garbage_collector.hpp:169:87: required from here
/usr/local/include/boost/property_map/property_map.hpp:200:7: error: no matching function for call to ‘get(gc::ref_color_map_wrapper&, long unsigned int&)’
/usr/local/include/boost/property_map/property_map.hpp:200:7: note: candidates are:
In file included from /usr/local/include/boost/tuple/tuple.hpp:33:0,
from /usr/local/include/boost/unordered/detail/allocate.hpp:27,
from /usr/local/include/boost/unordered/detail/buckets.hpp:15,
from /usr/local/include/boost/unordered/detail/table.hpp:10,
from /usr/local/include/boost/unordered/detail/equivalent.hpp:14,
from /usr/local/include/boost/unordered/unordered_set.hpp:17,
from /usr/local/include/boost/unordered_set.hpp:16,
from /usr/local/include/boost/graph/adjacency_list.hpp:21,
from ../include/garbage_collector.hpp:6,
from main.cpp:3:
/usr/local/include/boost/tuple/detail/tuple_basic.hpp:225:1: note: template<int N, class HT, class TT> typename boost::tuples::access_traits<typename boost::tuples::element<N, boost::tuples::cons<HT, TT> >::type>::const_type boost::tuples::get(const boost::tuples::cons<HT, TT>&)
/usr/local/include/boost/tuple/detail/tuple_basic.hpp:225:1: note: template argument deduction/substitution failed:
In file included from /usr/local/include/boost/graph/adjacency_list.hpp:36:0,
from ../include/garbage_collector.hpp:6,
from main.cpp:3:
/usr/local/include/boost/property_map/property_map.hpp:200:7: note: ‘gc::ref_color_map_wrapper’ is not derived from ‘const boost::tuples::cons<HT, TT>’
In file included from /usr/local/include/boost/tuple/tuple.hpp:33:0,
from /usr/local/include/boost/unordered/detail/allocate.hpp:27,
from /usr/local/include/boost/unordered/detail/buckets.hpp:15,
from /usr/local/include/boost/unordered/detail/table.hpp:10,
from /usr/local/include/boost/unordered/detail/equivalent.hpp:14,
from /usr/local/include/boost/unordered/unordered_set.hpp:17,
from /usr/local/include/boost/unordered_set.hpp:16,
from /usr/local/include/boost/graph/adjacency_list.hpp:21,
from ../include/garbage_collector.hpp:6,
from main.cpp:3:
/usr/local/include/boost/tuple/detail/tuple_basic.hpp:211:1: note: template<int N, class HT, class TT> typename boost::tuples::access_traits<typename boost::tuples::element<N, boost::tuples::cons<HT, TT> >::type>::non_const_type boost::tuples::get(boost::tuples::cons<HT, TT>&)
/usr/local/include/boost/tuple/detail/tuple_basic.hpp:211:1: note: template argument deduction/substitution failed:
In file included from /usr/local/include/boost/graph/adjacency_list.hpp:36:0,
from ../include/garbage_collector.hpp:6,
from main.cpp:3:
/usr/local/include/boost/property_map/property_map.hpp:200:7: note: ‘gc::ref_color_map_wrapper’ is not derived from ‘boost::tuples::cons<HT, TT>’
/usr/local/include/boost/property_map/property_map.hpp:179:19: note: template<class T> const T& get(const T*, std::ptrdiff_t)
/usr/local/include/boost/property_map/property_map.hpp:179:19: note: template argument deduction/substitution failed:
/usr/local/include/boost/property_map/property_map.hpp:200:7: note: mismatched types ‘const T*’ and ‘gc::ref_color_map_wrapper’
Graph definition
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS, vertex_info_type> graph_type;
What's working
boost::get(ref_color_map, *it);
boost::put(ref_color_map, *it, boost::white_color);
works without any compilation error…
You need to put your get() and put() functions in the namespace where ref_color_map resides, since they are found via ADL. See here.
I am playing with container types, gettingmore into the details and try to build an unmodifiable (or immutable) map.
For that, I built some kind like copy-constructor to add all elements from another unordered_map into my UnmodifiableMap (which is basically a wrapper for std::unordered_map). To make it unmodifiable, I only provide const iterators and read-only methods. But I get stuck with the constructor, I am sure I miss something, maybe somebody can point me the problem here. Maybe it is a totally wrong way like this, but his is what tried so far:
template <typename Key, typename T,
typename HashFcn = std::hash<Key>,
typename EqualKey = std::equal_to<Key>,
typename Alloc = std::allocator<std::pair<const Key, T> > >
class UnmodifiableMap {
public:
// The actual data
typedef std::unordered_map<T, Key, HashFcn, EqualKey> base;
typedef Key key_type;
typedef T data_type;
typedef T mapped_type;
typedef std::pair<const key_type, data_type> value_type;
typedef HashFcn hasher;
typedef EqualKey key_equal;
typedef Alloc allocator_type;
typedef typename base::size_type size_type;
typedef typename base::const_iterator const_iterator;
typedef typename base::iterator iterator;
private:
base _map;
/**
* Constructs an empty unordered_map
*/
UnmodifiableMap(
size_type n = 0, const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type &alloc = allocator_type())
: _map(n, hf, eql, alloc) {}
public:
/** Constructs a copy of unordered_map */
UnmodifiableMap(const base& other)
: _map(static_cast<const base&>(other)) {}
~UnmodifiableMap() {}
iterator begin() { return _map.begin(); }
iterator end() { return _map.end(); }
const_iterator begin() const { return _map.begin(); }
const_iterator end() const { return _map.end(); }
bool empty() const { return _map.empty(); }
bool contains(const key_type& key) const {
return _map.find(key) != _map.end(); }
};
And here the main body:
int main(int argc, char **argv) {
typedef std::unordered_map<int, std::string> Items;
Items map;
map[1] = "first string";
map[4] = "string 4";
map[5] = "string 5";
map[22] = "string 22";
map[12] = "string 12";
map[18] = "string 18";
typedef UnmodifiableMap<int, std::string> ReadOnlyItems;
ReadOnlyItems readonlymap(map);
return 0;
}
The error I get is
Unmodifiable_map.cpp: In function ‘int main(int, char**)’:
Unmodifiable_map.cpp:56:25: error: no matching function for call to ‘UnmodifiableMap<int, std::basic_string<char> >::UnmodifiableMap(Items&)’
Unmodifiable_map.cpp:56:25: note: candidates are:
Unmodifiable_map.h:45:2: note: UnmodifiableMap<Key, T, HashFcn, EqualKey, Alloc>::UnmodifiableMap(const base&) [with Key = int, T = std::basic_string<char>, HashFcn = std::hash<int>, EqualKey = std::equal_to<int>, Alloc = std::allocator<std::pair<const int, std::basic_string<char> > >, UnmodifiableMap<Key, T, HashFcn, EqualKey, Alloc>::base = std::unordered_map<std::basic_string<char>, int, std::hash<int>, std::equal_to<int>, std::allocator<std::pair<const std::basic_string<char>, int> > >]
Unmodifiable_map.h:45:2: note: no known conversion for argument 1 from ‘Items {aka std::unordered_map<int, std::basic_string<char> >}’ to ‘const base& {aka const std::unordered_map<std::basic_string<char>, int, std::hash<int>, std::equal_to<int>, std::allocator<std::pair<const std::basic_string<char>, int> > >&}’
Unmodifiable_map.h:37:2: note: UnmodifiableMap<Key, T, HashFcn, EqualKey, Alloc>::UnmodifiableMap(UnmodifiableMap<Key, T, HashFcn, EqualKey, Alloc>::size_type, const hasher&, const key_equal&, const allocator_type&) [with Key = int, T = std::basic_string<char>, HashFcn = std::hash<int>, EqualKey = std::equal_to<int>, Alloc = std::allocator<std::pair<const int, std::basic_string<char> > >, UnmodifiableMap<Key, T, HashFcn, EqualKey, Alloc>::size_type = long unsigned int, UnmodifiableMap<Key, T, HashFcn, EqualKey, Alloc>::hasher = std::hash<int>, UnmodifiableMap<Key, T, HashFcn, EqualKey, Alloc>::key_equal = std::equal_to<int>, UnmodifiableMap<Key, T, HashFcn, EqualKey, Alloc>::allocator_type = std::allocator<std::pair<const int, std::basic_string<char> > >]
Unmodifiable_map.h:37:2: note: no known conversion for argument 1 from ‘Items {aka std::unordered_map<int, std::basic_string<char> >}’ to ‘long unsigned int’
Unmodifiable_map.h:14:7: note: UnmodifiableMap<int, std::basic_string<char> >::UnmodifiableMap(const UnmodifiableMap<int, std::basic_string<char> >&)
Unmodifiable_map.h:14:7: note: no known conversion for argument 1 from ‘Items {aka std::unordered_map<int, std::basic_string<char> >}’ to ‘const UnmodifiableMap<int, std::basic_string<char> >&’
Unmodifiable_map.h:14:7: note: UnmodifiableMap<int, std::basic_string<char> >::UnmodifiableMap(UnmodifiableMap<int, std::basic_string<char> >&&)
Unmodifiable_map.h:14:7: note: no known conversion for argument 1 from ‘Items {aka std::unordered_map<int, std::basic_string<char> >}’ to ‘UnmodifiableMap<int, std::basic_string<char> >&&’
Hope somebody can shed some light on that. Also I think I need to do more in the copy constructor, propably copy the elements (like a swap function) and an implementaton of operator= ?!
You are swapping the role of T and Key in your base type definition inside your wrapper class:
template <typename Key, typename T,
typename HashFcn = std::hash<Key>,
typename EqualKey = std::equal_to<Key>,
typename Alloc = std::allocator<std::pair<const Key, T> > >
class UnmodifiableMap {
public:
// typedef std::unordered_map<T, Key, HashFcn, EqualKey> base; // ERROR
typedef std::unordered_map<Key, T, HashFcn, EqualKey> base; // OK
...
Hence, your underlying map ends up being an unordered_map<string, int> rather than an unordered_map<int, string>, and the compiler complains about the mismatch.
Also notice, that you have an unnecessary static_cast in your constructor:
UnmodifiableMap(const base& other)
// : _map(static_cast<const base&>(other)) {} // NOT NEEDED. Just do:
: _map(other) {}
I've attempted to write a brief utility functor that takes two std::pair items and tests for their equality, but disregarding the ordering of the elements. Additionally (and this is where I run into trouble) I've written a function to take a container of those std::pair items and test for membership of a given pair argument in a the container.
/* A quick functor way to check the identity of the two items of a pair to see if each pair contains the same items regardless of order */
template <class T>
class EqualPairs : public std::binary_function<T,T,bool> {
T arg2;
public:
explicit EqualPairs (const T& x) : arg2(x) { }
bool operator() (const T& arg1) {
bool same = false;
if (arg1 == arg2 || (arg1.first == arg2.second && arg1.second == arg2.first))
same = true;
return same;
}
};
/* checks to see if the give pair p is a member of the list of pairs l. The pairs are compared disregarding the order of the pair elements (i.e. (4,2) == (2,4)) */
template <class P>
bool PairListMember (const P& p, const std::vector<P>& l)
{
std::vector<P>::iterator it;
it = find_if (l.begin(), l.end(), EqualPairs<P>(p));
bool member_of_list = (it != l.end()) ? true : false;
return member_of_list;
}
I couldn't think of a clean way to allow for generic container selection, so I hard-coded a std::vector as the container type, for now. Help on making the container type generic would also be appreciated, but for now I'd just like to get the above to compile and work. The error I get is:
In function ‘bool PairListMember(const P&, const std::vector<P, std::allocator<_CharT> >&)’:
error: expected `;' before ‘it’
error: ‘it’ was not declared in this scope
In function ‘bool PairListMember(const P&, const std::vector<P, std::allocator<_CharT> >&) [with P = std::pair<int, int>]’:
error: dependent-name ‘std::vector<P,std::allocator<_CharT> >::iterator’ is parsed as a non-type, but instantiation yields a type
note: say ‘typename std::vector<P,std::allocator<_CharT> >::iterator’ if a type is meant
changing the code by adding a 'typename' as suggested only results in the following errors:
error: no match for ‘operator=’ in ‘it = std::find_if [with _InputIterator = __gnu_cxx::__normal_iterator<const std::pair<int, int>*, std::vector<std::pair<int, int>, std::allocator<std::pair<int, int> > > >, _Predicate = EqualPairs<std::pair<int, int> >](((const std::vector<std::pair<int, int>, std::allocator<std::pair<int, int> > >*)l)->std::vector<_Tp, _Alloc>::begin [with _Tp = std::pair<int, int>, _Alloc = std::allocator<std::pair<int, int> >](), ((const std::vector<std::pair<int, int>, std::allocator<std::pair<int, int> > >*)l)->std::vector<_Tp, _Alloc>::end [with _Tp = std::pair<int, int>, _Alloc = std::allocator<std::pair<int, int> >](), EqualPairs<std::pair<int, int> >(((const std::pair<int, int>&)((const std::pair<int, int>*)p))))’
/usr/include/c++/4.2/bits/stl_iterator.h:637: note: candidates are: __gnu_cxx::__normal_iterator<std::pair<int, int>*, std::vector<std::pair<int, int>, std::allocator<std::pair<int, int> > > >& __gnu_cxx::__normal_iterator<std::pair<int, int>*, std::vector<std::pair<int, int>, std::allocator<std::pair<int, int> > > >::operator=(const __gnu_cxx::__normal_iterator<std::pair<int, int>*, std::vector<std::pair<int, int>, std::allocator<std::pair<int, int> > > >&)
For your compiler error, you need to use the typename keyword.
typename std::vector<P>::iterator it;
iterator is a typename, i.e. it refers to an embedded type within std::vector. When you access a typename with the :: operator within a template, you need to use the typename keyword so the compiler knows it is the name of a type, as opposed to the name of some variable or function within the class.
Edit: Also, you need to use a const_iterator, because your vector is const in this case.
typename std::vector<P>::const_iterator it;
There are a couple of issues with your EqualPairs template. It derives from binary_function but isn't actually a binary_function because operator() only takes one argument. You can (and should) make operator() const as it doesn't modify the EqualPairs object.
I think that you can simplify it somewhat.
template<class T>
struct EqualPairs : public std::binary_function<T, T, bool>
{
bool operator()(const T& lhs, const T& rhs) const
{
return lhs == rhs || lhs.first == rhs.second && lhs.second == rhs.first;
}
};
Then you can use std::bind1st (or std::bind2nd) to make a predicate out of your binary function and the input parameter. Also, by making the function a 'one liner' you don't actually need to declare a temporary variable for the iterator, so getting const and typename correct isn't an issue.
template <class P>
bool PairListMember (const P& p, const std::vector<P>& l)
{
return l.end() != std::find_if(l.begin(), l.end(), std::bind1st(EqualPairs<P>(), p));
}
You can make this template more generic by taking an iterator type as a template parameter. This removes your dependency on std::vector.
template <class Iter>
bool PairListMember(const typename std::iterator_traits<Iter>::value_type& p, Iter first, Iter last)
{
return last != std::find_if(first, last, std::bind1st(EqualPairs<typename std::iterator_traits<Iter>::value_type>(), p));
}
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.