i can't compile the following code
namespace sequential_sort
{
template<class T>
void sort(std::list<T>& source)
{
sort(source.begin(), source.end()); //(1)
}
template<class Iter>
void sort(Iter begin, Iter end)
{
if(begin == end)
return;
typedef Iter::value_type value_type;
value_type value = *(begin);
Iter part = std::partition(begin, end, [&value](const value_type&->bool{return t < value;});
sort(begin, part);
Iter divide = part;
divide++;
sort(divide, end);
}
}
It says that at line (1) I have error C2688 ambiguous call to overloaded functions.
I can't understand why, overloaded functions even have different number of parameters?
There are a few issues at play:
1) You need to declare your single parameter sequential_sort::sort function before the two parameter one, unless you want to another sort function. You probably don't see the effect of this because you are using a Windows C++ compiler, which is not standards compliant in this respect. What should have happened is that std::sort was unambiguously picked, and that wouldn't compile because it requires random access iterators (std::list has a sort member function which you should use instead of std::sort).
2) Once that is fixed, since you are passing std::list iterators to the two parameter sort, argument dependent lookup (ADL) means std::sort is considered too. This is the cause of the ambiguity. You can fix this by being specific about which two-parameter sort you want to use:
#include <list>
#include <algorithm>
namespace sequential_sort
{
template<class Iter>
void sort(Iter begin, Iter end) { }
template<class T>
void sort(std::list<T>& source)
{
sequential_sort::sort(source.begin(), source.end()); //(1)
//^^^^^^^^^^^^^^^
}
}
Related
I want my function to be able to take array.begin() and array.end() as arguments. As far as I understand, the begin/end functions return a pointer to the first/last element of the array. Then why does the following code not work? How should I write the code instead?
#include <iostream>
#include <array>
template<class T> void foo(const T* begin, const T* end) {
...
}
int main() {
std::array<int, 5> arr = { 1, 2, 3, 4, 5 };
foo(arr.begin(), arr.end()); // <-- error!
return 0;
}
As far as I understand, the begin/end functions return a pointer to the first/last element of the array
No. begin and end return iterators. The standard library works with iterators. Iterators are a generalization of pointers.
Iterators behave like pointers and you use them like pointers (e.g. *it to access the element), with some caveats: not all iterators have all the operations a pointer does. A pointer satisfies the random access iterator concept, so on some implementations the iterator of std::array could be just an alias for the pointer type, but you can't rely on that. E.g. on the same compiler it can be a pointer for the release build, but a full class for the debug build.
The idiomatic way is to write:
template<class It>
void foo(It begin, It end) {
for (auto it = begin; it != end; ++it) {
const auto& elem = *it;
// ..
}
}
Since C++20 we should transition from iterator pairs to ranges:
void foo(std::ranges::range const auto& r) {
for (const auto& elem : r) {
// ...
}
}
As far as I understand, the begin/end functions return a pointer
Your understanding is (generally) wrong. begin and end functions return std::array::iterator, as per documentation. That type is not necessarily a pointer.
to the first/last element of the array
end isn't an iterator to the last element, but one past the last element.
how to solve my problem the right way?
Accept arguments of type std::array::iterator.
That said, given that foo is a template, there seems to be little reason to not allow the argument to be of any iterator type:
template<class It>
void
foo(It begin, It end)
Alternatively, you could accept a range:
template<class Range>
void
foo(const Range& range)
// usage
foo(arr);
I am implementing a function that wants to loop over a number of elements in an std::array, but I don't really care how long the std::array is. So I was thinking of the following function:
#include <stdio.h>
#include <array>
#include <iterator>
void foo(std::array<bool,0>::const_iterator begin, std::array<bool,0>::const_iterator end)
{
printf("iterator");
}
int main()
{
std::array<bool, 25> one;
std::array<bool, 33> two;
foo(one.cbegin(), one.cend());
foo(two.cbegin(), two.cend());
}
I am quite okay with this, except for the std::array<bool,0>. My question is, is there another way to specify the iterator that is required for this function?
Update
There are some things I should mention. Of course this code is part of a bigger scope and I tried to hide as much detail as I could.
I want to ensure that the iterator being used is of bools.
I am using C++14
The function is part of a class interface and I want to be able to handle multiple array sizes. I don't want to bother the implementors of the interface to know exactly what the size of the array is.
class MyInterface
{
public:
virtual foo(std::array<bool,0>::const_iterator begin, std::array<bool,0>::const_iterator end) = 0;
~MyInterface() = default;
};
I remembered that virtual functions cannot be templated. That means I would have to template my whole interface and that would exactly loose the point of why I was trying this in the first place.
You can just make it a function template as
template <typename I>
void foo(I begin, I end)
{
std::cout << "iterator";
}
You don't need to care about container type (and the size), you can pass iterators of std::array, std::vector and std::string and so on, even raw pointers (which also satisfies iterator's requirements).
Just use span:
#include <array>
#include <span>
class MyInterface {
public:
virtual void foo(std::span<bool> barr) = 0;
// interface destructors should be virtual
virtual ~MyInterface() = default;
};
void bar(MyInterface& interface) {
std::array<bool, 42> arr;
interface.foo(arr);
}
If you don't have access to a C++20 compiler, you may use gsl::span from gsl instead.
Use a template:
template <size_t N>
void foo(std::array<bool,N>::const_iterator begin, std::array<bool,N>::const_iterator end)
{
printf("iterator");
}
And now as long as both iterators come from an array of size N this function will work.
If you want to accept iterators from different sized arrays, you just need to add another template parameter for the second iterator like
template <size_t N, size_t M>
void foo(std::array<bool,N>::const_iterator begin, std::array<bool,M>::const_iterator end)
{
printf("iterator");
}
If the function accepts two iterators when the referring std::array is redundant. Just declare the function like
template <class Iterator>
void foo( Iterator first, Iterator last );
In the declaration you can name the iterator that corresponds to the used iterator type in the function like for example
template <class ForwardIterator>
void foo( ForwardIterator first, ForwardIterator last );
Or instead of the name ForwardIterator you could use the name BidirectionalIterator or RandomAccessIterator for self-documenting.
If you need to know the value type of the iterator you can use different approaches. For example
template <class Iterator>
void foo( Iterator first, Iterator last )
{
using value_type = typename std::iterator_traits<Iterator>::value_type;
if ( first != last )
{
value_type item1 = *first;
// or
auto item2 = *first;
//
const auto &item3 = *first;
//...
}
}
In this case you will have a flexible function definition. For example if in future you will change std::array<N, bool> to std::vector<bool> the function will as usual work.
I am trying to generalize a function I have which used to take two iterators to a vector of a specific data-structure, and re-arrange the elements in a certain way using std::iter_swap (like std::sort does).
Since this function only actually needs a subset of the data, and I will need to use it in other contexts in the future, I thought about removing the dependency on the data structure, and use boost::transform_iterator at the point of call to handle the transformation.
Unfortunately, it seems that boost::transform_iterator is not happy with this change. I can imagine why: std::iter_swap is usually implemented as std::swap(*lhs, *rhs), and dereferencing the transform_iterator does not yield the original element to swap in the correct way.
I was wondering if there was a way to handle this case. I am open to use boost::range or the experimental std::ranges ts if it needed.
This question is probably similar to this one, but even there the solution ends up modifying the subset of data the algorithm needs, rather than the outside structure.
Here is an MWE:
#include <boost/iterator/transform_iterator.hpp>
#include <vector>
#include <algorithm>
#include <iostream>
struct A {
int x;
int y;
};
template <typename It>
void my_invert(It begin, It end) {
while (begin < end) {
std::iter_swap(begin++, --end);
}
}
template <typename It>
void my_print(It begin, It end) {
for (; begin != end; ++begin)
std::cout << (*begin) << ' ';
std::cout << '\n';
}
int main() {
std::vector<int> x{7,6,5,4,3,2};
my_invert(std::begin(x), std::end(x));
my_print(std::begin(x), std::end(x));
auto unwrap = +[](const A & a) { return a.x; };
std::vector<A> y{{9,8}, {7,6}, {5,4}, {3,2}};
auto begin = boost::make_transform_iterator(std::begin(y), unwrap);
auto end = boost::make_transform_iterator(std::end(y), unwrap);
//my_invert(begin, end); // Does not work.
my_print(begin, end);
return 0;
}
Accessing the underlying iterator
You could access the base() property of transform_iterator (inherited publicly from iterator_adaptor) to implement your custom transform_iter_swap, for swapping the underlying data of the wrapped iterator.
E.g.:
template<class IteratorAdaptor>
void transform_iter_swap(IteratorAdaptor a, IteratorAdaptor b)
{
std::swap(*a.base(), *b.base());
}
template <typename It>
void my_invert(It begin, It end) {
while (begin < end) {
transform_iter_swap(begin++, --end);
}
}
After which your example (omitting the std::vector part) runs as expected:
my_invert(begin, end); // OK
my_print(begin, end); // 3 5 7 9
If you want a general function template to cover both the boost (adaptor) iterators as well as typical iterators, you could e.g. use if constexpr (C++17) based on whether the iterators public typedef iterator_category derives from boost::iterators::no_traversal_tag or not:
// expand includes with
#include <boost/iterator/iterator_categories.hpp>
template <class It>
void iter_swap(It a, It b) {
if constexpr(std::is_base_of<
boost::iterators::no_traversal_tag,
typename It::iterator_category>::value) {
std::swap(*a.base(), *b.base());
}
else {
std::swap(*a, *b);
}
}
template <typename It>
void my_invert(It begin, It end) {
while (begin < end) {
iter_swap(begin++, --end);
}
}
The problem comes from the unary predicate you've passed. Notice, that since you allow the return type to be deduced, the return type is deduced to be an int, a copy is returned, and the compilation fails when you try to swap two unmodifiable ints. However, if you were to specify the return type to be int&, like so:
auto unwrap = [](A & a)->int& { return a.x; }; // explicitly demand to return ref
It will compile, and reverse the elements. Tested on gcc 8.1.0 and clang 6.0.0.
I need to create a function which receives the iterator from the begin and the end of one container. Then it should show the content in the console.
My problem is that i dont know how to declare the iterator so that it can work with any type of container
This is what I did:
template <class T>
void print(typename iterator<T> &beg, typename iterator<T> &end) {
while (beg != end) {
cout << *beg << endl;
beg++;
}
}
The std::iterator class is really just a convenience; there's nothing in the standard that requires all iterators to inherit from it. Additionally, std::iterator doesn't have virtual methods, so it's not nearly the same thing as taking an Iterator<T> in, say, Java, where invoking the next() method would call the appropriate next(). You want to take a general type T, not just an std::iterator, so that the compiler will resolve to the correct overloads of operator++ and operator* at compile-time.
template <typename T>
void print(T iter, const T& end) {
// Taking the first argument by value ensures that
// we don't modify the caller's variables
while (iter != end) {
cout << *iter << endl;
++iter;
}
}
This will work for any forward iterators, which is what you're dealing with 99% of the time.
I need to create a function which receives the iterator from the begin
and the end of one container.
Look how standard functions do it, for example std::find:
template< class InputIt, class T >
InputIt find( InputIt first, InputIt last, const T& value );
Observations:
InputIt does not need to inherit from the (now obsolete) std::iterator class or any other class. Among other advantages, this allows the function to be used with an array.
The same iterator type is used for start and end.
The iterators are passed by value.
The template parameter does not specify the iterators' value type.
Just do it exactly like that in your own code and you'll be fine:
#include <iostream>
#include <vector>
template <class Iterator> // not T
void print(Iterator beg, Iterator end) {
while (beg != end) {
std::cout << *beg << '\n';
beg++;
}
}
int main() {
std::vector<int> const vec = { 1, 2, 3 };
int const array[] = { 1, 2, 3 };
using std::begin;
using std::end;
print(begin(vec), end(vec));
print(begin(array), end(array));
}
If I have a function which takes a std::vector<T>::const_iterator called begin and a std::vector<T>::const_iterator called end, is it possible for me to iterate over it in a backwards direction?
UPDATE
I can't change the function signature, which is like this:
void func(Foo::const_iterator begin, Foo::const_iterator end)
{
...
}
and called with:
func(foo.begin(), foo.end());
which I also can't change
Yes, you can.
template <typename Foo>
void test(typename Foo::const_iterator begin,
typename Foo::const_iterator end)
{
std::reverse_iterator<typename Foo::const_iterator>
rbegin(end),
rend(begin);
std::copy(rbegin, rend, std::ostream_iterator<typename std::iterator_traits<typename Foo::const_iterator>::value_type>(std::cout));
}
int main()
{
std::vector<int> v{3,1,4,1,5,9,2,6};
test<std::vector<int> >(v.begin(), v.end());
}
I may have misunderstood the question, but do you just need:
while (begin != end) {
--end;
// do something with *end
}
If you need an iterator that goes backwards, ipc's answer gives you one.
In practice with vector you could probably get away with while (begin != end--), but don't be tempted. It's undefined behavior to decrement an iterator in the case where it's at the start of the vector (i.e. when it's equal to the result of vector::begin()).
This code requires at least a BidirectionalIterator. Fortunately, vector has a RandomAccessIterator, which is even better.
If you genuinely only had a ForwardIterator, then you'd have to iterate over the range and store the iterator values somewhere (like a stack), and then use them in reverse order:
std::stack<Foo::const_iterator> iterators;
while (begin != end) {
iterators.push(begin);
++begin;
}
while (!iterators.empty()) {
Foo::const_iterator i = iterators.top();
// do something with *i
iterators.pop();
}
This code requires at least a ForwardIterator (it will not work with a mere InputIterator).
Yes, you can use std::reverse_iterator. It is also a good idea not
to specify the type of the iterator explicitly. Use a template
argument instead.
#include <vector>
#include <algorithm>
#include <iostream>
#include <iterator>
template <typename BidirectionalIterator>
void x(BidirectionalIterator b, BidirectionalIterator e) {
std::reverse_iterator<BidirectionalIterator> rb(e), re(b);
std::for_each(rb, re,
[](typename BidirectionalIterator::reference x)
{ std::cout << x << std::endl;});
}
int main()
{
std::vector<int> v{1,2,3,4};
x(begin(v), end(v));
return 0;
}