I'm not sure if the answers I was able to find are the easiest way to do what I need. The simple template that I would know how to modify into a full solution to my problem would be code that accomplishes the following:
Takes as input two iterators pointing to the beginning and end of an iterable container (vector, list...) containing things of value type T.
Returns a std::vector<T> containing an element-by-element copy of the input container in whatever order accomplished by iterating the input container from beginning to end.
Something non-functioning would be like follows:
template<typename Iterator, typename T>
std::vector<T> dumb_copy(Iterator first, Iterator last) { ... }
Problem is that I would need the compiler to somehow check that I'm given iterators pointing to something of type T.
I'm currently learning C++ and writing as practice the most generic implementations of certain algorithms that I can think of, so I want to get the best practices right from the start. If there's an easy way of doing this using C++11 constructs, that's fine with me.
You can simply use traits to remove the T type completely, allowing it to be determined automatically:
template <typename Iterator>
std::vector<typename std::iterator_traits<Iterator>::value_type>
dumb_copy(Iterator first, Iterator last)
{
std::vector<typename std::iterator_traits<Iterator>::value_type> copy;
// Populate the copy vector
return copy;
}
In particular, note that std::iterator_traits has a specialization when the iterator type is a pointer, so this will allow your function to "just work" even when it is passed pointers instead of "true" iterator objects.
You don't need to do this because the standard library containers already work this way. So you can create a std::vector from two iterators directly:
#include <string>
#include <vector>
#include <iostream>
int main()
{
std::string s = "hello"; // iterable container
// construct a vector using two iterators
std::vector<std::string::value_type> v(s.begin(), s.end());
// check the results
for(unsigned i = 0; i < v.size(); ++i)
std::cout << v[i];
std::cout << '\n';
}
You can just create a std::vector<T> with a type matching the result of *it for one of the iterators:
#include <type_traits>
#include <vector>
template <typename Iterator>
auto dump_copy(Iterator begin, Iterator end)
-> std::vector<typename std::decay<decltype(*begin)>::type> {
return std::vector<typename std::decay<decltype(*begin)>::type(begin, end);
}
With C++14 you can replace typename std::decay<X>::type by std::decay_t<X>.
Related
Here is my (simplified) attempt to implement a ranges::min_element version that would work for both lvalue and rvalue arguments:
#include <iterator>
#include <algorithm>
#include <type_traits>
#include <utility>
namespace better_std_ranges
{
template<typename Range>
constexpr auto min_element(Range& range)
{
using std::begin;
using std::end;
return std::min_element(begin(range), end(range));
}
template<typename Range>
constexpr auto min_element(Range&& range)
{
static_assert(!std::is_reference_v<Range>, "wrong overload chosen");
class _result_iterator_type // todo: inherit from some crtp base that will provide lacking operators depending on _underlying_iterator_type::iterator_category
{
using _underlying_iterator_type = std::decay_t<decltype(std::begin(std::declval<Range&>()))>;
public:
explicit constexpr _result_iterator_type(Range&& range) noexcept(std::is_nothrow_move_constructible_v<Range>)
: _underlying_range{std::move(range)}
, _underlying_iterator(::better_std_ranges::min_element(_underlying_range))
{
}
using difference_type = typename _underlying_iterator_type::difference_type;
using value_type = typename _underlying_iterator_type::value_type;
using pointer = typename _underlying_iterator_type::pointer;
using reference = typename _underlying_iterator_type::reference;
using iterator_category = typename _underlying_iterator_type::iterator_category;
constexpr decltype(auto) operator*() const
{
return *_underlying_iterator;
}
// todo: define other member functions that were not provided by the inheritance above
private:
Range _underlying_range;
_underlying_iterator_type _underlying_iterator;
};
return _result_iterator_type{std::move(range)};
}
}
#include <vector>
#include <iostream>
auto make_vector()
{
return std::vector{100, 200, 42, 500, 1000};
}
int main()
{
auto lvalue_vector = make_vector();
auto lvalue_vector_min_element_iterator = better_std_ranges::min_element(lvalue_vector);
std::cout << *lvalue_vector_min_element_iterator << '\n';
auto rvalue_vector_min_element_iterator = better_std_ranges::min_element(make_vector());
std::cout << *rvalue_vector_min_element_iterator << '\n';
}
The output is
42
42
Surely it lacks some implementation details, but the idea must be clear: if an input range is an rvalue, the return value can store a moved copy of it.
Thus it must be totally possible for std::ranges algorithms to work with rvalue arguments.
My question is: why does the standard go the opposite way and just prohibit using rvalue ranges with its algorithms by introducing that strange std::ranges::dangling placeholder?
There are two problems with this approach.
First, it breaks the semantics of the algorithm. The point of min_element (and any other algorithm that returns an iterator) is to return an iterator into the range. You're not doing that - you're returning an iterator into a different range. That really confuses the notion of what the return even means in this case. What would you even compare this iterator to? There's no corresponding .end()?
Second, the iterator model in C++ is based very strongly around the notion that iterators are cheap to copy. Every algorithm takes iterators by value and copies them around freely. Iterators are assumed to be light-weight and, importantly, non-owning. For forward iterators, copies of an iterator are assumed to be interchangeable.
Everything about this breaks if you suddenly have an iterator that has member std::vector<T> that it refers into. Copying iterators becomes very expensive. And now each distinct iterator copy is actually an iterator into a completely different range?
You can do a little bit better by having the iterator have a member std::shared_ptr<std::vector<T>> instead of a std::vector<T>. This way copies are much cheaper and no longer independent, so you have something closer to a legitimate iterator. But now you have to do an extra allocation (to create the shared pointer), you still have the issue where the iterator you're returning is into a different range than the algorithm was given, and you have the issue where the algorithm has very different semantics based on whether you provide an lvalue or rvalue range.
Basically, min_element on an rvalue range needs to either:
just return an iterator into the range, even if it will dangle
return some kind of wrapper around such a potentially-dangling iterator (this was the original Ranges design, dangling<I> could still let you get at the underlying I)
return some kind of type indicating that this doesn't work (the current design)
fail to compile entirely if usage would lead to dangling (what Rust would allow for)
I don't think there's another option here, really.
Is it possible to create in C++11 a function, which will accept any iterator as input argument in particular stl containers like vector or list?
I want to write something like
void f(iterator<int> i){
for (auto el : i)
cout << el;
}
int main(){
vector<int> v;
list<int> l;
...
f(v);
f(l);
}
Is it possible?
If you want your function to accept an iterator, then you cannot use the for (auto i: cont) syntax. Indeed, this new range-based for syntax wants the container, not an iterator.
Then, your can easily make your function a function template, passing the container.
template <class CONT>
void f(CONT &cont){
for (auto el : cont)
cout << el;
}
If you want to keep passing iterators, then you'll have to go the template way too, but you have to pass two iterators as arguments. One for the first, another for the last (just like the algorithm does).
template <class IT>
void f(IT first, IT last) {
for ( ; first!=last ; ++first)
cout << first;
}
No. You can write a function template that accepts any iterator as parameter, but not a function.
If you had a class that did type erasure for iterators then you could take that as a parameter. Here's an article and code for iterator type erasure.
There is a boost::any_iterator somewhere. But the Standard does not provide one.
If you are looking for a way to return a mostly unspecified iterator type (e.g. because the function signature in a base class can't fix the exact type of the iterator yet), you could have a look at C++: "Iterable<T>" interface
For example, the following is possible:
std::set<int> s;
std::set<int>::iterator it = s.begin();
I wonder if the opposite is possible, say,
std::set<int>* pSet = it->**getContainer**(); // something like this...
No, there is no portable way to do this.
An iterator may not even have a reference to the container. For example, an implementation could use T* as the iterator type for both std::array<T, N> and std::vector<T>, since both store their elements as arrays.
In addition, iterators are far more general than containers, and not all iterators point into containers (for example, there are input and output iterators that read to and write from streams).
No. You must remember the container that an iterator came from, at the time that you find the iterator.
A possible reason for this restriction is that pointers were meant to be valid iterators and there's no way to ask a pointer to figure out where it came from (e.g. if you point 4 elements into an array, how from that pointer alone can you tell where the beginning of the array is?).
It is possible with at least one of the std iterators and some trickery.
The std::back_insert_iterator needs a pointer to the container to call its push_back method. Moreover this pointer is protected only.
#include <iterator>
template <typename Container>
struct get_a_pointer_iterator : std::back_insert_iterator<Container> {
typedef std::back_insert_iterator<Container> base;
get_a_pointer_iterator(Container& c) : base(c) {}
Container* getPointer(){ return base::container;}
};
#include <iostream>
int main() {
std::vector<int> x{1};
auto p = get_a_pointer_iterator<std::vector<int>>(x);
std::cout << (*p.getPointer()).at(0);
}
This is of course of no pratical use, but merely an example of an std iterator that indeed carries a pointer to its container, though a quite special one (eg. incrementing a std::back_insert_iterator is a noop). The whole point of using iterators is not to know where the elements are coming from. On the other hand, if you ever wanted an iterator that lets you get a pointer to the container, you could write one.
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);
I would like to pass arbitrary container as an argument of function and iterate over it (no erasing nor pushing elements). Unfortunately it looks like there is no standard way of doing this.
First solution which comes to my mind is an interface (let's call it CollectionInterface) implemented by classes that will wrap STL containers. so the function declaration would look like:
f(const CollectionInterface * collection);
Or, I was thinking about method template, which has an advantage that it keeps binding at compilation time:
template <class CONTAINER> void f(const CONTAINER & collection);
Which way do you think is better?
ForwardIterator? This is a type of InputIterator (or OutputIterator) that also allows multi-pass algorithms (incrementing it does not invalidate prior values).
Iterators (which are quite different from Java iterators) are the central thread unifying C++ collections. For examples of algorithms working on them (and associated iterator type requirements), you can start with <algorithm>. In particular, search provides an example of using ForwardIterator. It finds the first occurrence within the range [first1, last1] of the sequence defined by the range [first2, last2). These are all objects meeting the requirements of ForwardIterator.
You can also write methods that accept the entire container instead of a reference if that's the way you want to handle things. Iterators into standard library containers are all provided via the member functions begin() and end(), or in some cases rbegin() and rend() for iterating backwards. The way templates work, you don't have to create an actual interface type that objects derive from; the requirements are instead inferred by the object is used.
template<typename Container> void Function(const Container& c) {
for(typename Container::const_iterator i = c.begin(), end = c.end(); i != end; ++i)
//do something
}
Passing iterators provide more flexibility when using the functions, particularly in that not all iterators come from containers with explicit begin() and end() functions, and you can provide whatever explicit subrange you want. But sometimes this method is appropriate.
I would like to pass arbitrary container as an argument of function and iterate over it (no erasing nor pushing elements).
Pass iterators. Here is an example for implementation and use:
template <typename Iter>
void function(Iter begin, Iter end)
{
for (Iter it = begin; it != end; ++it)
{
std::cout << *it << std::endl;
}
}
int main()
{
std::string array[] = {"hello", "array", "world"};
function(array, array + 3);
std::vector<std::string> vec = {"hello", "vector", "world"};
function(vec.begin(), vec.end());
}
Note that in many cases, you don't actually need to write the function, but you can compose it using the library facilities instead and then simply apply std::for_each on that. Or even better, use a preexisting algorithm like std::accumulate or std::find_if.