4

是否存在跨容器工作的一致元素访问语义,也许在提升中?类似于:

element_of(std_pair).get<1>();
element_of(boost_tuple).get<0>();
element_of(pod_array).get<2>();

原则上我可以自己写,但我不想重新发明轮子。谢谢

4

3 回答 3

2

容器有不同的访问方式,因为它们本质上是不同的。在 STL 中最接近的是迭代器。所有标准容器都有迭代器,因此您可以迭代它们并使用这些迭代器对它们使用相同的算法。但是,每个迭代器包含的内容因容器而异(必须只有元素,但映射有对)。而且,如果您将 pair 视为一个容器,它不会与其他容器相适应,因为它没有迭代器。

在大多数情况下,使用迭代器可以解决问题。但是,它显然并没有完全解决问题,STL 也没有针对它的解决方案。Boost可能,但我不知道有一个。

The main point, however, is that containers are inherently different and to a great extent are not meant to be interchangeable. By using standard iterators, most containers can be swapped for one another fairly easily. But it doesn't generally make sense to swap one container for another without changing some of the code around it because they act so differently. I believe that Scott Meyers makes a point of this in his book "Effective STL."

If you're really trying to make the various containers interchangeable, I'd suggest rethinking that and looking more closely at what you're doing. Odds are that that's not the best idea. Now, it may very well be a good idea for your particular application - I certainly can't say without knowing anything about it, and you'd be the best judge of that - but in the general case, making containers truly interchangeable is a bad idea. Iterators make it possible to reuse many algorithms on them, but even there, the type of algorithms that you can use on a particular container varies depending on the type of iterators that that container uses (random access, bi-directional, etc.).

So, no, I'm not aware of a pre-existing solution for accessing container elements other than iterators, but generally speaking, I'd advise against attempting it. Containers are not truly interchangeable and are not meant to be.

于 2010-01-23T19:36:08.490 回答
1

我不知道有任何通用访问器可以跨 C++ 中所有已知的容器定义工作。但是,Boost.Range在某种程度上可以这样使用。

为了获得更好的灵活性,您可能需要自己实现它。也许沿着这个抓一些东西:

struct container_accessor { ... }
template <typename Container>
container_accessor make_accessor(Container& c) { ... }

template <typename Container>
container_const_accessor make_accessor(Container const& c) { ... }

where 然后为您需要的所有容器专门化 container_accessor。

于 2010-01-23T18:34:34.530 回答
1

I'm not aware of such a thing.

You could most probably just implement a free get function for the types you're interested in. Boost.Tuple already has it. std::pair has it in C++0x. And the rest shouldn't be too complicated.

E.g

#include <iostream>
#include <utility>
#include <vector>
#include <boost/tuple/tuple.hpp>

namespace getter
{
    template <size_t Index, class Container>
    typename Container::reference get(Container& c)
    {
        return c[Index];
    }

    template <size_t Index, class Container>
    typename Container::const_reference get(const Container& c)
    {
        return c[Index];
    }

    template <size_t Index, class T>
    T& get(T *arr)
    {
        return arr[Index];
    }

    namespace detail {
        template <size_t Index, class T, class U>
        struct PairTypeByIndex;

        template <class T, class U>
        struct PairTypeByIndex<0u, T, U>
        {
            typedef T type;
            type& operator()(std::pair<T, U>& p) const { return p.first; }
            const type& operator()(const std::pair<T, U>& p) const { return p.first; }
        };

        template <class T, class U>
        struct PairTypeByIndex<1u, T, U>
        {
            typedef U type;
            type& operator()(std::pair<T, U>& p) const { return p.second; }
            const type& operator()(const std::pair<T, U>& p) const { return p.second; }
        };
    }

    template <size_t Index, class T, class U>
    typename detail::PairTypeByIndex<Index, T, U>::type& get(std::pair<T, U>& p)
    {
        return detail::PairTypeByIndex<Index, T, U>()(p);
    }

    template <size_t Index, class T, class U>
    const typename detail::PairTypeByIndex<Index, T, U>::type& get(const std::pair<T, U>& p)
    {
        return detail::PairTypeByIndex<Index, T, U>()(p);
    }

    using boost::get;
}

int main()
{
    boost::tuple<int, int> tuple(2, 3);
    std::cout << getter::get<0>(tuple) << '\n';
    std::vector<int> vec(10, 1); vec[2] = 100;
    std::cout << getter::get<2>(vec) << '\n';
    const int arr[] = {1, 2, 3, 4, 5};
    std::cout << getter::get<4>(arr) << '\n';
    std::pair<int, float> pair(41, 3.14);
    ++getter::get<0>(pair);
    const std::pair<int, float> pair_ref = pair;
    std::cout << getter::get<0>(pair_ref) << ' ' << getter::get<1>(pair_ref) << '\n';
}
于 2010-01-24T00:05:52.630 回答