Reputation: 106
I have a struct called Edge
with memebers pair<double,double> s
and pair<double,double> e
.
In the main
function,I have an vector of edges vector<Edge> edges
.
I populate that with Edge
objects.
Now I want to find the index of a particular Edge x
.
So I wrote a function :
int indexOf(vector<Edge>& arr,Edge& k);
Body of function is irrelevant here. Now my question is, How can make the function work like :
edges.indexOf(x)
without having to pass the vector of edges as a parameter?
Upvotes: 0
Views: 119
Reputation: 27385
Now my question is, How can make the function work like
edges.indexOf(x)
Since inheriting a std::vector is not a good solution (it adds caveats to the inherited code) the good solution is to encapsulate your vector:
class EdgeSequence // or another name
{
public:
size_t indexOf(const Edge& x) const
{
return std::distance(
begin(),
std::find(begin(), end(), x));
}
auto begin() const { return data.begin(); }
auto end() const { return data.end(); }
// TODO: add other functions you used on your initial vector
private:
std::vector<Edge> data;
};
without having to pass the vector of edges as a parameter?
EdgeSequence edges; // TODO: fill with data
auto index = edges.indexOf(your_edge);
Upvotes: 3
Reputation: 4076
I've also given this a stab. I must say I quite like what one is able to do in c# in that case.
I've tried to stay clear of inheritance and the answer here elaborates why. In general I rarely inherit implementation (or extend as c# calls it).
One can create a class like IndexCheckable below that wraps the container. Presently it is only implemented for vector, but one can easily implement it for other containers too (and use other algorithms to determine the index).
IndexCheckable has a clear responsibility and gives checkability to it's container. One can also hide it behind an interface that hides the type of the container (not shown in example)
#include <iostream>
#include <vector>
#include <algorithm>
template <class T, class Allocator = std::allocator<T>>
struct IndexCheckable {
const std::vector<T,Allocator>& indexable_;
IndexCheckable(const std::vector<T,Allocator>& indexable)
: indexable_(indexable) {
}
int indexOf(const T& item) const {
auto i = std::find(indexable_.begin(), indexable_.end(), item);
return i == indexable_.end() ? -1 : i - indexable_.begin();
}
};
template <class T, class Allocator =
std::allocator<T>> IndexCheckable<T,Allocator> indexCheckable(const std::vector<T,Allocator>& indexable) {
return IndexCheckable<T,Allocator>{indexable};
}
void foo(const IndexCheckable<int>& indexCheckable) {
//Voilla. Check works!!!
indexCheckable.indexOf(5);
}
int main() {
std::vector<int> ivect{0, 1, 2, 5, 6};
foo(ivect);
// or...
auto r1 = indexCheckable(ivect).indexOf(5);
std::cout << "r1: " << r1 << std::endl; //Expects 3
auto r2 = indexCheckable(ivect).indexOf(10);
std::cout << "r2: " << r2 << std::endl; //Expects -1
return 0;
}
I've also decided to elaborate on the idea of hiding IndexCheckable behind and interface and implementing this for different containers. From a usage perspective, a client of the code just has to specify that something must be IndexCheckable (and oblivious of the container type):
#include <iostream>
#include <vector>
#include <list>
#include <array>
#include <algorithm>
#include <iterator>
template <class T>
struct IndexCheckable {
virtual int indexOf(const T& item) const = 0;
protected: ~IndexCheckable(){}
};
template <
template <class, class> class C, //Container
class T, //Item
class A = std::allocator<T>
>
struct IndexCheckableImpl : public IndexCheckable<T> {
const C<T, A>& indexable_;
IndexCheckableImpl(const C<T, A>& indexable)
: indexable_(indexable) {
}
int indexOf(const T& item) const override {
auto i = std::find(indexable_.begin(), indexable_.end(), item);
return i == indexable_.end() ? -1 : std::distance(indexable_.begin(), i);
}
};
template <template<class,class> class C, class T, class A = std::allocator<T>>
IndexCheckableImpl<C,T,A> indexCheckable(const C<T,A>& indexable) {
return IndexCheckableImpl<C,T,A>{indexable};
}
void testItem(const IndexCheckable<int>& indexCheckable, const char* name) {
auto r1 = indexCheckable.indexOf(5);
std::cout << "Test " << name << ": r1: " << r1 << std::endl; //Expects 3
auto r2 = indexCheckable.indexOf(10);
std::cout << "Test " << name << ": r2: " << r2 << std::endl; //Expects -1
}
template <class Container>
void test(const Container& container, const char* name) {
auto checkable = indexCheckable(container);
testItem(checkable, name);
}
int main() {
test(std::vector<int>{0, 1, 2, 5, 6}, "vector");
test(std::list<int>{0, 1, 2, 5, 6}, "list");
return 0;
}
Upvotes: 0
Reputation: 187
buddy u can do this my providing the default value at function definition example :- int indexOf(Edge& k,vector& arr = yourVector);
but just make sure you declare the yourVector as golbal variable and put value in yourVector before using the function. If u want sample code comment me.
Upvotes: -1
Reputation: 46
Maybe inherit std::vector?
#include <iostream>
#include <vector>
using namespace std;
struct Edge
{
Edge(double _s, double _e) : s(_s), e(_e) {}
double s;
double e;
};
bool operator==(const Edge &lhs, const Edge &rhs) {
return lhs.s == rhs.s && lhs.e == rhs.e;
}
class MyVector : public vector<Edge>
{
public:
int index_of(const Edge &e)
{
for (int i = 0; i < this->size(); ++i) {
if (this->at(i) == e)
return i;
}
return -1;
}
};
int main()
{
MyVector v;
for (int i = 0; i < 10; ++i)
v.emplace_back(i, i);
cout << v.index_of(v.at(5)) << endl;
return 0;
}
Upvotes: 3