5

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

現時点では、クラスの任意のサブクラスで実際にvectorset、またはを返すことしかできません。ただし、一部については、たとえば aを使用して、この制限を緩和できます。mapInterfacevectorgsl::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;
};

問題は、array_view他のコンテナ タイプで使用するための代替手段があるかどうかです。基本的に私が欲しいのは、特定のコンテナー タイプを指定せずに、不変ビューとして機能する関数から返すことができる軽量オブジェクトだけです。std::seta を のようなものに押し込むことも理にかなっていますarray_viewが、サポートされている操作は少なくなります (たとえば、ランダムアクセスはありません)。mapは明らかに別の獣であり、別のviewサポートする連想ルックアップが必要mapになりますが、array_view<const std::pair<const int, int>>. 求めすぎですか?それとも、これを実装するための合理的な方法がありますか? それとも、そのような「ビュー」の既存の実装さえあるのでしょうか?

PS: 継承は前提条件ではありません。問題を提示する最も簡単な方法だと思いました。

4

2 に答える 2

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
}

悪用しようとしても:

sum(std::map<int, int>{})

エラーメッセージはひどいものではありません:

/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));
                                                            ^

ユース ケースのエイリアスを作成できます。

template <typename T>
using FwdImmutableRangeT = boost::any_range<T,
                               boost::forward_traversal_tag,
                               const T&, std::ptrdiff_t>;

そしてそれらを返します:

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;
};
于 2015-10-28T11:51:02.120 に答える