[英]Function that works on vector of class objects in C++
我有一個名為Edge
的結構,其中包含成員pair<double,double> s
和pair<double,double> e
。
在main
的 function 中,我有一個邊vector<Edge> edges
。 我用Edge
對象填充它。
現在我想找到特定Edge x
的索引。 於是我寫了一個function:
int indexOf(vector<Edge>& arr,Edge& k);
function 的主體在這里無關緊要。 現在我的問題是,如何使 function 像這樣工作:
edges.indexOf(x)
無需將邊向量作為參數傳遞?
也許繼承 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;
}
現在我的問題是,如何讓 function 像
edges.indexOf(x)
一樣工作
由於繼承 std::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;
};
無需將邊向量作為參數傳遞?
EdgeSequence edges; // TODO: fill with data
auto index = edges.indexOf(your_edge);
我也給了這個刺。 我必須說,在這種情況下,我非常喜歡在 c# 中能夠做的事情。
我試圖避開 inheritance , 這里的答案詳細說明了原因。 一般來說,我很少繼承實現(或擴展為 c# 調用它)。
可以創建一個 class 像下面的 IndexCheckable 來包裝容器。 目前它僅針對向量實現,但也可以輕松地為其他容器實現它(並使用其他算法來確定索引)。
IndexCheckable 有明確的責任,並為其容器提供可檢查性。 也可以將其隱藏在隱藏容器類型的界面后面(示例中未顯示)
#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;
}
我還決定詳細說明將 IndexCheckable 隱藏在和接口后面並為不同的容器實現它的想法。 從使用的角度來看,代碼的客戶只需要指定某些東西必須是 IndexCheckable (並且忽略容器類型):
#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;
}
伙計你可以做到這一點,我在 function 定義示例中提供默認值:- int indexOf(Edge& k,vector& arr = yourVector);
但只需確保在使用 function 之前將 yourVector 聲明為 gobal 變量並將值放入 yourVector 中。 如果你想要示例代碼評論我。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.