C++使用函数式代替泛型迭代器设计接口

C++使用函数式代替泛型迭代器设计接口

C++ 标准库使用迭代器作为索引下一值的部件。这在许多方面是有利的。

比如我们有一个生成平方列表的函数:


template <typename _Iter>
vector<int> get_square_list(_Iter begin, _Iter end)
{
    vector<int> v;
    for (auto iter = begin; iter != end; ++iter) {
        auto e = *iter;
        v.push_back(e * e);
    }
    return v;
}

int main(void)
{
    vector<int> v { 1, 2, 3, 4, 5 };
    list<int> l { 5, 4, 3, 2, 1 };

    auto vlist = get_square_list(v.begin(), v.end());
    auto llist = get_square_list(l.begin(), l.end());

    for (auto e : vlist) {
        cout << e << endl;
    }
    for (auto e : llist) {
        cout << e << endl;
    }
}

以上示例证明,在泛型编程中,使用模板+迭代器的接口,具有很大的优势。

但是,当我们将泛型迭代器引入类中,作为对象保存时,优势就没那么明显了:

template <typename _Iter>
class GetNextSquareValue
{
public:
    GetNextSquareValue(_Iter begin, _Iter end)
        : begin(begin), end(end), iter(begin) {}

    int get_next() {
        assert(iter != end);

        auto e = *iter;
        ++iter;
        return e * e;
    }

private:
    _Iter begin;
    _Iter end;
    _Iter iter;
};

int main(void)
{
    vector<int> v { 1, 2, 3, 4, 5 };
    list<int> l { 5, 4, 3, 2, 1 };

    GetNextSquareValue<vector<int>::iterator> vlist(v.begin(), v.end());
    GetNextSquareValue<list<int>::iterator> llist(l.begin(), l.end());

    for (int i = 0; i != v.size(); ++i) {
        cout << vlist.get_next() << endl;
    }
    for (int i = 0; i != l.size(); ++i) {
        cout << llist.get_next() << endl;
    }
}

如上代码实现了列表的部分转换。(只有当调用get_next()的时候才进行转换。)因为是惰性求值,保存求值的状态是很重要的。

显然,这里 vlist 和 llist 并不是一个类型,不利于保存。当然,我们可以构建基类、构建通用迭代器等来解决这个问题。但是,与其繁琐地寻求简便地保存迭代器处理办法,为什么不在一开始就不保存迭代器呢?

class GetNextSquareValue
{
public:
    GetNextSquareValue(std::function<int ()> get_next_value)
        : get_next_value(get_next_value) {}

    int get_next() {
        auto e = get_next_value();
        return e * e;
    }

private:
    std::function<int ()> get_next_value;
};

int main(void)
{
    vector<int> v { 1, 2, 3, 4, 5 };
    list<int> l { 5, 4, 3, 2, 1 };

    auto viter = v.begin();
    auto liter = l.begin();
    GetNextSquareValue vlist([&]() {
        assert(viter != v.end());
        auto r = *viter;
        ++viter;
        return r;
    });
    GetNextSquareValue llist([&]() {
        assert(liter != l.end());
        auto r = *liter;
        ++liter;
        return r;
    });

    for (int i = 0; i != v.size(); ++i) {
        cout << vlist.get_next() << endl;
    }
    for (int i = 0; i != l.size(); ++i) {
        cout << llist.get_next() << endl;
    }
}

C++ 11 支持了 lambda 表达式。 lambda 表达式可以便利地实现函数式程序设计。如上就是一个很好的 class 与 lambda 结合的例子。

当然,我们也可以进一步地,完全使用函数式来编写上述程序(其中使用了C++14的auto返回值):

template <typename _Iter>
auto make_iterNext(_Iter begin, _Iter end)
{
    _Iter iter = begin;
    return [=]() mutable {
        assert(iter != end);
        auto r = *iter;
        ++iter;
        return r;
    };
}

auto make_getNextValue(std::function<int ()> get_next_value) {
    return [=]() mutable {
        auto e = get_next_value();
        return e * e;
    };
}

int main(void)
{
    vector<int> v { 1, 2, 3, 4, 5 };
    list<int> l { 5, 4, 3, 2, 1 };

    auto vf = make_getNextValue(make_iterNext(v.begin(), v.end()));
    auto lf = make_getNextValue(make_iterNext(l.begin(), l.end()));

    for (int i = 0; i != v.size(); ++i) {
        cout << vf() << endl;
    }
    for (int i = 0; i != l.size(); ++i) {
        cout << lf() << endl;
    }
}

上面的例子可以看出,函数式与面向对象式程序设计,都是程序设计的一种方法。函数式与面向对象式,很多时候只是考虑问题的角度不同。没有一种永远好的方法,我们应该做的,是巧妙利用各种方法来解决各类问题。

©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值