2010-01-23 42 views
4

有没有,也许在boost,一致的元素访问语义跨容器? 东西沿着线:C++容器/数组/元组一致访问接口

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

原则上我可以写我自己,但我宁愿做重复的工作wheel.thanks

回答

1

我不知道这样的事情。

你可能很可能只是为你感兴趣的类型实现一个免费的get函数。Boost.Tuple已经拥有了它。 std::pair在C++ 0x中有它。其余的不应太复杂。

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'; 
} 
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) { ... } 

在哪里,然后专门为您需要的所有容器container_accessor。

+0

我认为元组,对等,可能会使用这种方法,因为它们可能包含不同类型是有问题的。但我想他们可以专门研究包装。 – Anycorn 2010-01-23 18:42:23

+0

@unknown是的,这可能会很棘手,你是对的。问题是如何为不同性质的容器指定通用访问器,可用于同类和异类容器。 – mloskot 2010-01-23 19:38:42

2

容器有不同的访问方式,因为它们本质上不同。你在STL中最接近的是迭代器。所有的标准容器都有迭代器,所以你可以遍历它们并使用这些迭代器在它们上使用相同的算法。但是,每个迭代器包含的内容取决于容器(必须只有元素,但映射具有对)。如果你将pair看作一个容器,那么它就不适合其余的,因为它没有迭代器。

在大多数情况下,使用迭代器解决了这个问题。但是,它显然不能完全解决问题,STL也没有解决方案。提升可能,但我不知道其中之一。

但是,要点是容器本质上不同,在很大程度上并不意味着可以互换。通过使用标准的迭代器,大多数容器可以很容易地彼此交换。但是换一个容器换另一个容器通常没有意义,因为它们的行为如此不同。我相信Scott Meyers在他的书“Effective STL”中提到了这一点。

如果你真的想让各种容器互换,我建议重新考虑一下,并且仔细观察你正在做的事情。可能性是,这不是最好的主意。现在,对于您的特定应用程序来说,这可能是一个好主意 - 我当然不会不知道任何关于它的事情,而且您会是最好的评判者 - 但在一般情况下,使容器真正可互换是馊主意。迭代器可以在其上重用许多算法,但即使在这种情况下,您可以在特定容器上使用的算法类型也会因该容器使用的迭代器类型(随机访问,双向等)而异。

所以,不,我没有意识到访问除迭代器以外的容器元素的预先存在的解决方案,但一般来说,我建议不要试图尝试它。容器并不是真正可以互换的,并不意味着是。

+0

“在大多数情况下,使用迭代器解决问题” - Boost.Range是一种抽象,它使用迭代器访问容器时提供了另一个级别的通用性。 – mloskot 2010-01-23 19:40:39

+0

好吧,我是用于矩阵操作的原型库,有时可以使用不同的容器作为索引,范围等。使用户侧的事情变得容易 – Anycorn 2010-01-23 19:47:21

+0

但对和元组不是容器。允许用户指定不同的容器是好的,迭代器(或Boost.Range)允许你将它抽象出来。 – jalf 2010-01-23 23:54:00