How to receive a iterator pair in a method? - c++

How can I receive a iterator pair in my own function/method?
void moveMessages(const std::InputIterator<uint64_t> begin, const std::InputIterator<uint64_t> end, uint32_t to_folder_id, int32_t from_folder=-1);
Im trying like this, bug gcc dont like it.. Probably i am missing something important..
I found somewhere a template version to do this. It is possible to do this without templates? Probably its enogh to receive an "input iterator base class" as a parameter, but how to do this?

I found somewhere a template version to do this.
Yes, that's how to do it.
template <typename InputIterator>
void moveMessages(InputIterator begin, InputIterator end, uint32_t to_folder_id, int32_t from_folder=-1);
It is possible to do this without templates?
Not really. Different kinds of iterators are different, unrelated types, so you need a template to handle them polymorphically.
Probably its enogh to receive an "input iterator base class" as a parameter, but how to do this?
There is no base class. In fact, iterators are not necessarily class types at all: pointers can be used as iterators.

Related

How to use `boost::range` iterators with standard iterators

I have functions that take in std::vector iterators, as in
typedef std::vector<Point> Points;
Points ConvexHull(Points::const_iterator first, Points::const_iterator last);
I usually pass the std iterators to them, but occasionally I need to work with boost iterators, such as boost::join's range iterator. How should I change the parametrizations of my functions, ideally without templates, so that they accept both iterators? Moreover, how do I indicate in each type which iterator concepts I need?
I tried looking at the boost::range documentation but it's overwhelmingly confusing for me and I don't know where to start.
For example, I couldn't find the difference between boost::range_details::any_forward_iterator_interface and boost::range_details::any_forward_iterator_wrapper, and whether I should use either of those to specify that I need a forward iterator.
Edit:
If I use boost::any_range, how can I pass non-const lvalue references?
For example:
template<typename T>
using Range = boost::any_range<T, boost::random_access_traversal_tag,
T, std::ptrdiff_t>;
f(Range<Point> &points); // defined elsewhere
// -------------
vector<Point> vec;
f(vec); // error; cannot bind non-const lvalue reference to unrelated type
boost-range has the any_range for this purpose and it suits both purposes for your case.
https://www.boost.org/doc/libs/1_60_0/libs/range/doc/html/range/reference/ranges/any_range.html
From your example it would look like this:
#include <boost/range/any_range.hpp>
typedef boost::any_range<Point,
boost::bidirectional_traversal_tag,
Point,
std::ptrdiff_t
> PointRange;
You should strongly consider using a template. Doing so let's the compiler keep useful information about what operations are actually occurring, which greatly helps it generate optimised output. The std:: convention is to name the type parameter for the concept required. E.g.
template< class BidirIt, class UnaryPredicate > // anything bidirectional (which includes random access)
BidirIt std::partition( BidirIt first, BidirIt last, UnaryPredicate p );
If you really don't want a template, you still shouldn't name anything in a detail namespace. Something like
#include <boost/range/any_range.hpp>
using PointRange = boost::any_range<Point, boost::random_access_traversal_tag>; // or another traversal tag.
using PointIterator = PointRange::iterator;
You will likely need to pass PointRange & less frequently than, say, int *&. Almost always passing by value is the correct behaviour. It is cheap to copy, as it holds a begin and end iterator from the Range that it was constructed from, nothing more.

How to overload std::remove for std::list?

I once learnt that the general way to erase elements from a container is via the erase-remove-idiom. But I was surprised to find out that at least g++'s STL implementation does not overload std::remove() for std::list, since in this case a lot of object assignments could be saved by doing the reordering via pointer manipulation.
Is there a reason that the C++ standard does not mandate such an optimisation? But my main question is how I can overload std::remove() (it does not have to be portable beyond g++), so I could provide an implementation that use list::splice()/list::merge() instead. I tried a couple of signatures but get an ambiguity error at best, for example:
template <typename T>
typename std::list<T>::iterator
remove(typename std::list<T>::iterator first,
typename std::list<T>::iterator last, const T &v);
P.S.: I am sorry that I was not clear enough. Please ignore that the functions come from the std namespace and what they do specifically. I just wish to learn more about the template/typetraits/overload rules in C++.
It's not mandated because it's not just an optimization, it has different semantics from what you'd expect for a Sequence container:
std::list<int> l;
l.push_back(1);
l.push_back(2);
std::list<int>::iterator one = l.begin();
std::list<int>::iterator two = l.end(); --two;
if (something) {
l.erase(remove(l.begin(), l.end(), 1), l.end());
// one is still valid and *one == 2, two has been invalidated
} else {
l.remove(1);
// two is still valid and *two == 2, one has been invalidated
}
Regarding the actual question: ISWYM, I'm stuck for the moment how to write a pair of function templates so that one matches arbitrary iterators and the other matches list iterators, without ambiguity.
Do be aware that there isn't actually any guarantee in the standard that list<T>::iterator is a different type from some_other_container<T>::iterator. So although in practice you'd expect each container to have its own iterator, in principle the approach is flawed quite aside from the fact that you suggested putting the overload in std. You can't use iterators alone to make "structural" changes to their corresponding containers.
You can do this without ambiguity:
template <typename Container>
void erase_all(Container &, const typename Container::value_type &);
template <typename T>
void erase_all(std::list<T> &, const T &);
list::remove or list::erase alone will do what you've seen the erase/remove idiom do for vectors.
remove for values or predicates. erase for single iterators or ranges.
The advice you received is good, but not universal. It is good for std::vector, for instance, but completely innecessary for std::list since std::list::erase() and std::list::remove() already do the right thing. They do all the pointer magic you request, something std::vector::erase() cannot do because its internal storage is different. This is the reason why std::remove() is not specialised for std::list: because there is no need to use it in this case.

Set custom comparison type

I am using multisets (sets would be the same), and have them as arguments to a bunch of functions. My functions looked like this:
void insert(const int val, multiset<int>& low, multiset<int>& high)
Then I found out I needed a custom comparison function for one of the multisets. I did it declaring a struct and overriding the () operator.
My multiset definition that once was: multiset<int> low now is multiset<int, order> low.
The problem with this is that I'm actually changing the type of low, and thus I need to change it in every single parameter, which greatly reduces the generality of my functions (the functions do not need to know the comparison method of the multiset).
Moreover, order is one comparison function, which is different from any other comparison functions I might ever declare (even though the types it compare are the exact same).
What I mean is that multiset<int, order1> != multiset<int, order2>, which is very bad.
So, my question is, how can I not have this problem? How can I declare functions that accept multisets (or sets) regardless of their comparison function?
You could use function templates:
template <typename M1, typename M2>
void insert(const int val, M1& low, M2& high);
Another option, if you want to restrict yourself to std::multiset<int, X>, is to use template template parameters.
If possible, I would use templates to take an arbitrary container or iterators.
If you really need it to not be a template and be able to deal with different types of multiset, boost::any_range provides a type-erased container abstraction that might be useful.

Varying argument values and number -- is this legal C++?

I'm trying to declare the following two functions to put back together a tokenized string (broken up into a vector or other iterator-compatible data structure):
std::string ComposeTokens(std::vector<std::string> Tokens);
std::string ComposeTokens(std::iterator first, std::iterator last);
In the implementation file (not provided here -- it's fairly obvious), Visual Studio's IntelliSense isn't recognizing either implementation as valid, saying that both conflict with both declarations. Compiling produces a message that iterators must have a template.
Is there any way to do what I'm trying to, here? Would it work to declare iterator< string >, do I need pointers, etc.? And has the STL or Boost or some other library already done this?
std::iterator is a base class template which at least needs a category and a class type defined.
You don't generally define iterators this way - you define it using templates:
template <typename Iterator>
std::string ComposeTokens(Iterator first, Iterator last);
Also, you probably want to be passing your vector by reference:
std::string ComposeTokens(std::vector<std::string>& Tokens);
Just make your iterator function a template:
template <class Iterator>
std::string ComposeTokens(Iterator first, Iterator last);
You can use std::accumulate:
#include <algorithm>
#include <vector>
#include <string>
#include <iostream>
int main() {
std::vector<std::string> v{"put", "me", "together"};
std::cout << std::accumulate(v.begin(), v.end(), std::string()) << std::endl;
}
It's perfectly ok to overload methods. VS is not complaining about that.
I think it's complaining because you're not using iterators correctly.
When you ask a question about a compiler error it's best to post the actual error, you'll get better answers.
As for iterators, they are templated and std::iterator is incomplete, hence the error. If your iterators are supposed to come from a vector then use std::vector<std::string>::iterator instead.
std::iterator is not what you think it is.
The easiest solution would be:
template <typename Iter>
std::string ComposeTokens(Iter first, Iter last);

Is it allowed to cast unordered_map to map?

As title says, is it allowed? If not, are they sharing the same interface or abstract class anyway? I did not find any reference from online documents. but looks unordered_map and map are using the same functions.
No, they're totally different and even if you force it with reinterpret_cast, it'll just go horribly wrong at runtime (ie, the dreaded Undefined Behaviour).
They're both STL containers, so deliberately have consistent interfaces.
That doesn't mean they're the same thing internally.
They're two unrelated types. If you want to construct one based on the other, you need to use constructors that take iterator range (C++11):
template <class InputIterator>
map(InputIterator first, InputIterator last,
const Compare& comp = Compare(), const Allocator& = Allocator());
template <class InputIterator>
unordered_map(InputIterator f, InputIterator l,
size_type n = see below,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
STL classes do not use virtual functions; there is no consistent base class you can cast through (ie, there's no equivalent to Java's java.util.Map). You can't cast between std::unordered_map and std::map any more than you could cast between HashMap and TreeMap in java - they're completely different types and cannot be used equivalently.
If you want a function to be able to take multiple types of STL containers, just use a template function:
template<typename Map>
void somefunc(Map &mymap) {
// ...
}
You can reinterpret cast one thing to any other thing, even if it makes no sense. The compiler won't stop you if you force it, which is essentially what reinterpret cast is. Casting map to unordered_map makes no sense & won't work.
Why do you want to cast map to unordered_map? They have the same interface. You gain nothing by casting it.