地图、集合等的 array_view 替代方案

Ros*_*lav 5 c++ c++11 c++14 array-view cpp-core-guidelines

假设我有一些类层次结构,其中有几个virtual函数返回容器引用:

#include <vector>
#include <set>
#include <map>
#include <unordered_set>
#include <unordered_map>

class Interface {
public:
    virtual const std::vector<int>& getArray() const = 0;
    virtual const std::set<int>& getSet() const = 0;
    virtual const std::map<int, int>& getMap() const = 0;
};

class SubclassA : public Interface {
public:
    const std::vector<int>& getArray() const override { return _vector; }
    const std::set<int>& getSet() const override { return _set; }
    const std::map<int, int>& getMap() const override { return _map; }

private:
    std::vector<int> _vector;
    std::set<int> _set;
    std::map<int, int> _map;
};
Run Code Online (Sandbox Code Playgroud)

目前,它是唯一可能实际上返回vectorsetmap在任何子Interface类。但是,对于vector部分,我可以使用例如 agsl::array_view来软化此限制:

class Interface {
public:
    virtual gsl::array_view<const int> getArray() const = 0;
    virtual const std::set<int>& getSet() const = 0;
    virtual const std::map<int, int>& getMap() const = 0;
};

class SubclassA : public Interface {
public:
    gsl::array_view<const int> getArray() const override { return _vector; }
    const std::set<int>& getSet() const override { return _set; }
    const std::map<int, int>& getMap() const override { return _map; }

private:
    std::vector<int> _vector;
    std::set<int> _set;
    std::map<int, int> _map;
};

class SubclassB : public Interface {
public:
   gsl::array_view<const int> getArray() const override { return _array; }
//    const std::set<int>& getSet() const override { return _set; }
//    const std::map<int, int>& getMap() const { return _map; }

private:
    std::array<int, 3> _array;
    std::unordered_set<int> _set;
    std::unordered_map<int, int> _map;
};
Run Code Online (Sandbox Code Playgroud)

所以问题是,是否有array_view其他容器类型的替代品?基本上我想要的只是一个轻量级对象,我可以从一个函数返回它,该函数将充当某个容器的不可变视图,而无需指定特定的容器类型。将 a 推std::set到类似 an 的东西对我来说甚至是有意义的array_view,但支持的操作较少(例如,没有随机访问)。map显然是一个不同的野兽,需要不同的view支持关联查找,但即使对于一个map我认为有能力说array_view<const std::pair<const int, int>>. 我要求太多了吗?或者也许有合理的方法来实现这一点?或者甚至可能存在此类“视图”的现有实现?

PS:继承不是先决条件 - 我只是认为这是提出问题的最简单方法。

Bar*_*rry 4

如果您只是寻找类型擦除的范围,您可以查看boost::any_range

using IntRange = boost::any_range<
                     int,
                     boost::forward_traversal_tag,
                     int,
                     std::ptrdiff_t>;

int sum(IntRange const& range) {
    return std::accumulate(range.begin(), range.end(), 0);
}

int main()
{
    std::cout << sum(std::vector<int>{1, 2, 3}) << std::endl;  // OK, 6
    std::cout << sum(std::set<int>{4, 5, 6}) << std::endl;     // OK, 15
}
Run Code Online (Sandbox Code Playgroud)

即使您尝试滥用它:

sum(std::map<int, int>{})
Run Code Online (Sandbox Code Playgroud)

错误消息并不可怕:

/usr/local/include/boost/range/detail/any_iterator_wrapper.hpp:40:60: error: invalid static_cast from type 'std::pair<const int, int>' to type 'int&'
             return static_cast<Reference>(const_cast<T&>(x));
                                                            ^
Run Code Online (Sandbox Code Playgroud)

您可以为您的用例创建一个别名:

template <typename T>
using FwdImmutableRangeT = boost::any_range<T,
                               boost::forward_traversal_tag,
                               const T&, std::ptrdiff_t>;
Run Code Online (Sandbox Code Playgroud)

并返回那些:

class Interface {
public:
    virtual FwdImmutableRange<int> getArray() const = 0;
    virtual FwdImmutableRange<const int> getSet() const = 0;
    virtual FwdImmutableRange<std::pair<const int, int>> getMap() const = 0;
};
Run Code Online (Sandbox Code Playgroud)