2010-01-23 43 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