2010-01-23 15 views
4

Existe-t-il, peut-être en boost, une sémantique d'accès aux éléments cohérente qui fonctionne à travers les conteneurs? quelque chose le long des lignes de:Interface d'accès cohérent C++ container/array/tuple

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

en principe je peux écrire moi-même, mais je préfère ne pas réinventer les wheel.thanks

Répondre

1

Je ne suis pas au courant d'une telle chose.

Vous pourriez très probablement mettre en œuvre juste une fonction get gratuit pour les types qui vous intéressent. Boost.Tuple a déjà. std::pair l'a en C++ 0x. Et le reste ne devrait pas être trop compliqué.

par exemple

#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

Je ne suis pas au courant de accesseurs générique qui fonctionnerait dans tous connus définitions des conteneurs en C++. Cependant, Boost.Range peut être utilisé en tant que tel dans une certaine mesure.

Pour une meilleure flexibilité, vous devrez probablement l'implémenter vous-même. Peut-être rayer quelque chose le long de ceci:

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

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

où puis spécialisez container_accessor pour tous les conteneurs dont vous avez besoin.

+0

je pense tuple, paire, etc. pourrait être problématique en utilisant cette approche, car ils peuvent contenir différents types.mais je suppose qu'ils peuvent être spécialisés dans l'emballage. – Anycorn

+0

@unknown Oui, cela peut être difficile, vous avez raison. Le problème est de savoir comment spécifier des accesseurs communs pour des conteneurs de nature différente, utilisables avec des conteneurs à la fois homogènes et hétérogènes. – mloskot

2

conteneurs ont différentes façons d'y accéder parce qu'ils sont fondamentalement différents. Le plus proche que vous obtenez dans le STL sont des itérateurs. Tous les conteneurs standards ont des itérateurs, donc vous pouvez les parcourir et utiliser les mêmes algorithmes sur eux en utilisant ces itérateurs. Cependant, ce que contient chaque itérateur dépend du conteneur (il doit simplement avoir l'élément, mais les cartes ont des paires). Et si vous regardez la paire comme un conteneur, ça ne va pas s'adapter au reste car il n'y a pas d'itérateurs.

Dans la plupart des cas, l'utilisation d'itérateurs résout le problème. Cependant, cela ne résout évidemment pas complètement le problème, et le STL n'a pas de solution pour cela. Boost peut, mais je n'en connais pas.

Le point principal, cependant, est que les conteneurs sont intrinsèquement différents et dans une large mesure ne sont pas destinés à être interchangeables. En utilisant des itérateurs standards, la plupart des conteneurs peuvent être échangés assez facilement les uns avec les autres. Mais il n'est généralement pas logique d'échanger un conteneur contre un autre sans modifier le code qui l'entoure, car ils agissent de manière si différente. Je crois que Scott Meyers fait un point dans son livre "Effective STL".

Si vous êtes vraiment essayer de faire les différents conteneurs interchangeables, je vous suggère de repenser et que regarder de plus près ce que vous faites. Les chances sont que ce n'est pas la meilleure idée. Maintenant, il peut très bien être une bonne idée pour votre application particulière - je ne peux certainement pas dire sans rien savoir à ce sujet, et vous seriez le meilleur juge de cela - mais dans le cas général, faire des récipients vraiment interchangeables est un mauvaise idée. Les itérateurs permettent de réutiliser de nombreux algorithmes, mais même là, le type d'algorithmes que vous pouvez utiliser sur un conteneur particulier varie en fonction du type d'itérateurs que ce conteneur utilise (accès aléatoire, bidirectionnel, etc.).

Donc, non, je ne suis pas au courant d'une solution pré-existante pour accéder à des éléments de conteneurs autres que itérateurs, mais en général, je vous le déconseille tenter. Les conteneurs ne sont pas vraiment interchangeables et ne sont pas destinés à l'être.

+0

"Dans la plupart des cas, l'utilisation d'itérateurs résout le problème" - Boost.Range est une abstraction qui fournit un autre niveau de généricité dans l'accès aux conteneurs en utilisant des itérateurs. – mloskot

+0

Eh bien, je suis une bibliothèque de prototypage pour les manipulations matricielles et parfois été en mesure d'utiliser différents conteneurs pour les indices, la gamme, etc. rend les choses un peu plus faciles côté utilisateur – Anycorn

+0

Mais les paires et les tuples ne sont pas des conteneurs. Permettre à l'utilisateur de spécifier différents conteneurs est très bien, et les itérateurs (ou Boost.Range) vous permettent d'abstraire cela. – jalf