簡體   English   中英

Function 適用於 C++ 中 class 對象的向量

[英]Function that works on vector of class objects in C++

我有一個名為Edge的結構,其中包含成員pair<double,double> spair<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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM