适用于 C++ 中 class 个对象向量的函数

Function that works on vector of class objects in C++

我有一个名为 Edge 的结构,成员 pair<double,double> spair<double,double> e

main 函数中,我有一个边向量 vector<Edge> edges。 我用 Edge 个对象填充它。

现在我想找到特定 Edge x 的索引。 所以我写了一个函数:

int indexOf(vector<Edge>& arr,Edge& k);

函数体在这里无关紧要。 现在我的问题是, 如何使函数像这样工作:

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;
}

兄弟你可以做到这一点我在函数定义中提供默认值 例子 :- int indexOf(Edge& k,vector& arr = yourVector);

但请确保在使用该函数之前将 yourVector 声明为 golbal 变量并将值放入 yourVector 中。如果你想要示例代码评论我。

我也试了一下。我必须说我非常喜欢在那种情况下用 c# 可以做的事情。

我尽量避免继承,答案 here 详细说明了原因。一般来说,我很少继承实现(或扩展为 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;
}

Now my question is, How can make the function work like 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;
};

without having to pass the vector of edges as a parameter?

EdgeSequence edges; // TODO: fill with data
auto index = edges.indexOf(your_edge);