C++ Vector Range Constructor - c++

I was looking over some C++ documentation when it occurred to me that the vector container doesn't have a constructor that 'easily' allows the user to pass a range of values - a min and a max - and have a vector constructed which has elements from min -> max. I thought this was odd so I tried writing my own and discovered it was non-trivial. Here's my solution.
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
template <typename T>
class MyIterator: public std::iterator<std::input_iterator_tag, int>
{
public:
MyIterator(T val):value(val) {}
MyIterator(const MyIterator & m):value(m.value) {}
MyIterator& operator ++()
{
++value;
return *this;
}
MyIterator operator ++(int)
{
MyIterator temp(*this);
operator ++();
return temp;
}
bool operator ==(const MyIterator & m) const { return value == m.value; }
bool operator !=(const MyIterator & m) const { return !(value == m.value); }
T& operator *() { return value; }
private:
T value;
};
int main(int argc, char** argv)
{
std::vector<int> my_vec(MyIterator<int>(100), MyIterator<int>(400));
std::copy(my_vec.begin(), my_vec.end(), std::ostream_iterator<int>(std::cout, "\n"));
return 0;
}
Does the new C++ have a solution for this?

In C++11 there is the std::iota function. Otherwise you have e.g. std::fill and std::fill_n, or std::generate and std::generate_n.

For C++11 there was no substantial work on changing the algorithms or containers to make them easier usable (there are a couple of new algorithms and the containers were made aware of allocators and rvalues). Neither is there a substantial change for C++14.
There is some hope for C++17, though: the Ranges Study Group is looking at concepts to make the algorithms and containers easier to use. That said, it isn't clear where that journey will travel to.

Related

random_access_iterator does not convert to input_iterator in std::any_if

the code below is an adoption from here and implements a user-defined random access iterator for a class holding a dynamic array in a shared pointer. In member function any the std::any_if, which requires an input_iterator, is called. From my knowledge and comments here using a random_access_iterator instead of an input_iterator should be perfectly legal. Unfortunately it does not compile with g++ and clang++ with the error message:
In file included from iterator.cpp:1:
In file included from /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/11.1.0/../../../../include/c++/11.1.0/iostream:39:
In file included from /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/11.1.0/../../../../include/c++/11.1.0/ostream:38:
In file included from /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/11.1.0/../../../../include/c++/11.1.0/ios:40:
In file included from /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/11.1.0/../../../../include/c++/11.1.0/bits/char_traits.h:39:
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/11.1.0/../../../../include/c++/11.1.0/bits/stl_algobase.h:2065:25: error: invalid operands to binary expression ('xx<long long>::Iterator' and 'xx<long long>::Iterator')
__trip_count = (__last - __first) >> 2;
It compiles when the iterator category is changed to input_iterator.
Any ideas about the root of the problem are highly appreciated.
#include <iostream>
#include <iterator>
#include <algorithm>
#include <memory>
using namespace std;
template <typename T>
class xx{
struct Iterator
{
using iterator_category = std::random_access_iterator_tag;
//using iterator_category = std::input_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = T;
using pointer = T*;
using reference = T&;
Iterator(pointer ptr) : m_ptr(ptr) {}
reference operator*() const { return *m_ptr; }
pointer operator->() { return m_ptr; }
Iterator& operator++() { m_ptr++; return *this; }
Iterator operator++(int) { Iterator tmp = *this; ++(*this); return tmp; }
friend bool operator== (const Iterator& a, const Iterator& b) { return a.m_ptr == b.m_ptr; };
friend bool operator!= (const Iterator& a, const Iterator& b) { return a.m_ptr != b.m_ptr; };
private:
pointer m_ptr;
};
protected:
std::shared_ptr<T[]> m_data;
int n=0;
public:
xx()=default;
xx(int n):n{n}{m_data=shared_ptr<T[]>(new T[n]);};
~xx(){};
Iterator begin() { return Iterator(&m_data.get()[0]); }
Iterator end() { return Iterator(&m_data.get()[n]); }
const int sz()const{return(n);}
void any(xx<long long int> &id){
if(any_of(id.begin(),id.end(),[this](long long int i){return(i<0 || i>(this->sz()-1));})){
std::string msg="error";throw msg;
}
}
};
int main(){
xx<double> x(10);int i=0;
xx<long long int> y(5);
cout<<x.sz()<<endl;
for(auto s=x.begin();s!=x.end();++s){
*s=(double)i++;
}
i=0;
for(auto s=y.begin();s!=y.end();++s){
*s=i++;
}
for(auto i : x){
cout<<i<<endl;
}
x.any(y);
return(0);
}
A random access iterator is one that (a) has the random access iterator tag, and (b) fullfills the requirements of being a random access iterator.
Yours fails on (b).
You need to implement [] - and + and related and < etc. And obey the other rules and requirements with them.
The tag determines which implementation your iterator is dispatched to; yours fails to provide expected features for the iterator category you claim to have, so it breaks.
The standard states that lying about your iterator category means passing your iterator in makes your program ill formed, no diagnostic required. In this case, an optimized implementation that works faster on random access iterators exists, but breaks on your lie.

C++ binary search for a class

I have a class and I want to implement binary_search (from library) to it:
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
class T_value{
public:
T_value(const int _timestamp, const string _value) :
timestamp(_timestamp),
value(_value)
{}
int get_time() {return timestamp;}
private:
int timestamp;
string value;
};
int main()
{
T_value one(1, "one"),
two(3, "two"),
three(43, "three"),
four(-1, "four");
vector<T_value> v{one,two,three, four};
cout << binary_search(begin(v), end(v), 3);
}
Is that possible? Should I overload '==' and '<' operators (tried, didn't succeed) or something else?
Thank you in advance!
Since you send an int as the 3rd argument to binary_search,
just an operator< will not be enough, because you need to
support both int<T_value and T_value<int
The suggestion is to create a comparator class with the members:
bool operator()(const T_value& lhs, int rhs) const
bool operator()(int lhs, const T_value& rhs) const
and send an instance as a fourth parameter.
Furthermore, the vector should be sorted before binary_search is
invoked. You could do this with std::sort, but now you need to
support a 3rd type of comparison, a 3rd member of the comparator
class could do that, like:
bool operator()(const T_value& lhs, const T_value& rhs) const
The end result might look something like this
Yes. Although you just need to implement operator<. Also the argument to binary_search is mismatched and the container must be pre-sorted.
Link to working example:
http://coliru.stacked-crooked.com/a/0343dd205abac6f2
Operator less:
bool operator<(const T_value& other) const {
return timestamp < other.timestamp;//you may wan't another sort criteria
}
Pre-sort container and binary_search:
std::sort(v.begin(), v.end());
cout << (binary_search(begin(v), end(v), T_value(3, "not used") ) ? "found" : "not found") << std::endl;

Finding a C++ object in the set by object comparision instead of using functors

I want to populate a std::set of GraphNode objects and check if another GraphNode with the same value exists in the set. In Java, objects can be compared by overloading equals and compareTo methods, instead of creating some functor object. I implemented operator==(T& t) and expected to find the object in the set like this,
std::find(nodesSet->begin(),nodesSet->end(), new GraphNode<T>(1))!=nodesSet->end())
But I am not getting the break point in neither == nor ()() operator functions. Why is it so? Is there a way to find the object by object comparison?
template<class T>
class GraphNode
{
friend class Graph<T>;
friend bool operator==(GraphNode<T>& node1, GraphNode<T>& node2);
private:
T t;
std::vector<GraphNode<T>*> adjNodes;
public:
bool operator==(T& t);
};
template<class T>
inline bool GraphNode<T>::operator==(T & t)
{
return this->t == t ? true : false;
}
template<class T>
inline bool operator==(GraphNode<T>& node1, GraphNode<T>& node2)
{
return node1.t == node2.t ? true : false;
}
void populate()
{
std::set<GraphNode<T>*>* nodesSet = new set<GraphNode<T>*>;
nodeSet->insert(new GraphNode<T>(1));
nodeSet->insert(new GraphNode<T>(2));
if ( std::find( nodesSet->begin(),nodesSet->end(),
new GraphNode<T>(1) ) != nodesSet->end() )
{
cout<<"found value";
}
}
As aschepler pointed out, the problem with your code is that you end up comparing pointers, not objects. std::find (look at the possible implementations in the linked page), if called without a predicate, uses the == operator to compare what is returned when the iterators you give it are dereferenced. In your case, you have a std::set<GraphNode<T>*> nodesSet, so the type of *nodesSet.begin() is GraphNode<T>*, not GraphNode<T> (note the lack of star). In order for you to be able to use the == operator defined for your GraphNode, you need to have your set be std::set<GraphNode<T>>, that is of objects of your type rather than of pointers.
If you have to store pointers in your set (e.g. because you don't want to copy the objects), you can write a wrapper for pointers that uses the comparison operator for the underlying class of the pointers. Here's an example:
#include <iostream>
#include <set>
#include <algorithm>
class obj {
int i;
public:
obj(int i): i(i) { }
bool operator<(const obj& o) const { return i < o.i; }
bool operator==(const obj& o) const { return i == o.i; }
int get() const { return i; }
};
template <typename T>
class ptr_cmp {
T* p;
public:
ptr_cmp(T* p): p(p) { }
template <typename U>
bool operator<(const ptr_cmp<U>& o) const { return *o.p < *p; }
template <typename U>
bool operator==(const ptr_cmp<U>& o) const { return *o.p == *p; }
T& operator*() const { return *p; }
T* operator->() const { return p; }
};
int main(int argc, char* argv[])
{
obj five(5), seven(7);
std::set<ptr_cmp<obj>> s;
s.insert(&five);
s.insert(&seven);
obj x(7);
std::cout << (*std::find(s.begin(),s.end(), ptr_cmp<obj>(&x)))->get()
<< std::endl;
return 0;
}
It turned out that my compiler (gcc 6.2.0) required both operator== and operator< for std::find to work without a predicate.
What is wrong with using a predicate though? It is a more generalizable approach. Here's an example:
#include <iostream>
#include <set>
#include <algorithm>
class obj {
int i;
public:
obj(int i): i(i) { }
bool operator==(const obj& o) const { return i == o.i; }
int get() const { return i; }
};
template <typename T>
struct ptr_cmp {
const T *l;
ptr_cmp(const T* p): l(p) { }
template <typename R>
bool operator()(const R* r) { return *l == *r; }
};
template <typename T>
ptr_cmp<T> make_ptr_cmp(const T* p) { return ptr_cmp<T>(p); }
int main(int argc, char* argv[])
{
obj five(5), seven(7);
std::set<obj*> s;
s.insert(&five);
s.insert(&seven);
obj x(7);
std::cout << (*std::find_if(s.begin(),s.end(), make_ptr_cmp(&x)))->get()
<< std::endl;
return 0;
}
Note, that make_ptr_cmp allows you to avoid explicitly stating the type, so you can write generic code.
If you can use C++11, use can just use a lambda function instead of ptr_cmp,
std::find_if(s.begin(),s.end(), [&x](const obj* p){ return *p == x; } )
std::find compares the values pointed at by the iterators. These values are pointers, not objects. So none of them will be equal to new GraphNode<T>(1), which is a brand new pointer to a brand new object.
As others have stated, you are comparing pointers, which won't work as expected, it's doing comparisons on addresses in memory. The operation a < b has a valid meaning for a pointer but will order the elements by their location in memory, not on their contained data elements and also no elements will be unique, as they will all have unique addresses. That is unless you try to insert the same element twice.
The above issue however will be hidden by using std::find, which iterates over all the elements in the container anyway. If you are using a set, you should be aspiring to get logarithmic time look ups for elements, so should use sets own find function, which knows that its a binary tree under the hood.
In C++, the equivalent of Object#equals is operator== (as you knew) and in the context of associative containers the equivalent of Object#compareTo is operator<. Object#equals and operator== work in the same way, exactly as you expect; If somethings equal its equal, simple to understand. Object#compareTo and operator< are used by algorithms in different ways, operator< is used to implement strict weak ordering to determine if one element is less than or greater than another.
So to allow your elements to be usable in a set you will need an overridden operator< in your GraphNode class. Once you have this you can use the std::set::find function to find elements in your set and it will find them in O(log n) time rather than linear time.
These algorithms are designed on the assumption they are working on value types, i.e not pointers but those things that are pointed to. So to use pointers you need to define a new comparison function that basically dereferences the pointers before applying the comparison (either == or <).
Some example code
#include <algorithm>
#include <iostream>
#include <set>
#include <vector>
template<typename>
class Graph
{
};
template<class T>
class GraphNode
{
friend class Graph<T>;
friend bool operator==(const GraphNode<T>& a, const GraphNode<T>& b);
private:
T t;
std::vector<GraphNode<T>*> adjNodes;
public:
explicit GraphNode(const T& tval)
:t(tval)
{}
T& getT(){ return t; }
const T& getT() const { return t; }
bool operator==(const T& t);
friend bool operator<(const GraphNode& a, const GraphNode& b){
return a.t < b.t;
}
};
template<class T>
inline bool GraphNode<T>::operator==(const T& t)
{
return (this->t == t);
}
template<class T>
inline bool operator==(const GraphNode<T>& a, const GraphNode<T>& b)
{
return (a.t == b.t);
}
int main()
{
using IntGraphNode = GraphNode<int>;
std::set<IntGraphNode> nodesSet;
nodesSet.insert(IntGraphNode(1));
nodesSet.insert(IntGraphNode(2));
auto findit = nodesSet.find(IntGraphNode(1));
if(findit != nodesSet.end())
{
std::cout << "found value\n";
}
auto findit2 = std::find_if(
nodesSet.begin(),
nodesSet.end(),
[](IntGraphNode i) { return i.getT() == 1;});
if(findit2 != nodesSet.end())
{
std::cout << "found value aswell\n";
}
}
The first search uses sets own find function and the second uses std::find_if, which takes a predicate (function that returns either true or false) to test equality. The second example also removes the need to make a dummy object, by exposing the T object and using that in the comparison lambda function.
Also a comment about
std::find(nodesSet->begin(),nodesSet->end(), new GraphNode<T>(1))!=nodesSet->end())
There are quite a few conceptual misunderstandings in this line. Firstly std::find does not take a comparison function, that would be std::find_if, but the compiler will tell you that (in its own especially indirect and verbose way). Also the comparison function is evaluated in the algorithm, you are trying to evaluate it at the call site. The other thing is unlike java, you can't just fire off newed objects into oblivion. That's a memory leak, you no longer have any variable storing the newed value, so you can't delete it.

How to define iterator for a special case in order to use it in a for loop using the auto keyword

I would like to define the subsequent code in order to be able to use it like
"for (auto x:c0){ printf("%i ",x); }"
But I do not understand something and i have searched it for some time.
The error I get is:
error: invalid type argument of unary ‘*’ (have ‘CC::iterator {aka int}’)
#include <stdio.h>
class CC{
int a[0x20];
public: typedef int iterator;
public: iterator begin(){return (iterator)0;}
public: iterator end(){return (iterator)0x20;}
public: int& operator*(iterator i){return this->a[(int)i];}
} ;
int main(int argc, char **argv)
{ class CC c0;
for (auto x:c0){
printf("%i ",x);
}
printf("\n");
return 0;
}
It seems you are trying to use int as you iterator type using the member operator*() as the deference operations. That won't work:
The operator*() you defined is a binary operator (multiplication) rather than a unary dereference operation.
You can't overload operators for built-in types and an iterator type needs to have a dereference operator.
To be able to use the range-based for you'll need to create a forward iterator type which needs a couple of operations:
Life-time management, i.e., copy constructor, copy assignment, and destruction (typically the generated ones are sufficient).
Positioning, i.e., operator++() and operator++(int).
Value access, i.e., operator*() and potentially operator->().
Validity check, i.e., operator==() and operator!=().
Something like this should be sufficient:
class custom_iterator {
int* array;
int index;
public:
typedef int value_type;
typedef std::size_t size_type;
custom_iterator(int* array, int index): array(array), index(index) {}
int& operator*() { return this->array[this->index]; }
int const& operator*() const { return this->array[this->index]; }
custom_iterator& operator++() {
++this->index;
return *this;
}
custom_iterator operator++(int) {
custom_iterator rc(*this);
this->operator++();
return rc;
}
bool operator== (custom_iterator const& other) const {
return this->index = other.index;
}
bool operator!= (custom_iteartor const& other) const {
return !(*this == other);
}
};
You begin() and end() methods would then return a suitably constructed version of this iterator. You may want to hook the iterator up with suitable std::iterator_traits<...> but I don't think these are required for use with range-based for.
Dietmar Kühl explained well why your code does not work: you cannot make int behaving as an iterator.
For the given case, a suitable iterator can be defined as a pointer to int. The following code is tested at ideone:
#include <stdio.h>
class CC{
int a[0x20];
public: typedef int* iterator;
public: iterator begin() {return a;}
public: iterator end() {return a+0x20;}
} ;
int main(int argc, char **argv)
{
class CC c0;
int i = 0;
for (auto& x:c0){
x = ++i;
}
for (auto x:c0){
printf("%i ",x);
}
printf("\n");
return 0;
}

C++ Sort Algorithm for data structures [duplicate]

This question already has an answer here:
Ordered sort in STL containers
(1 answer)
Closed 9 years ago.
I want to use the stl sort algorithm to sort some numbers, but i also want to remember their initial position.
I have a data structure like this:
struct Numbers {
int position;
int value;
};
I have created a vector of Numbers like this:
vector<Numbers> a;
How to use the stl sort algorithm, such that i sort the data structures based on the value?
You can use a functor too :
struct comp {
bool operator()(const Numbers &lhs, const Numbers& rhs) const{
lhs.value < rhs.value;
}
};
std::sort(a.begin(),a.end(), comp());
With C++11, you can use a lambda function :
std::sort( a.begin() , a.end() ,
[](const Numbers& lhs , const Numbers& rhs)
{ return lhs.value < rhs.value; }
);
You'll need to overload the "<" operator, like so:
bool Numbers::operator<(Numbers temp)
{
return value < temp.value;
}
Use std::sort and provide a custom comparator (template arg Compare)
#include <algorithm>
#include <vector>
//...
std::vector<Numbers> a;
//fill the vector a and set Numbers::position of each element accordingly...
struct {
bool operator()(const Numbers& a,const Numbers& b)const
{
return a.value < b.value;
}
} my_comparator;
std::sort(a.begin(),a.end(),my_comparator);
//...