Domanda

I dont think my title is accurate so just go to the code.

namespace Fobaizer
{
  template <typename T, typename C>
  static T GetItemFromContainer(const C &container) {
    T item = container[0]; // do something. 0 or iterator
    return item;
  }
}

Example:

MyClass myClass = Fobaizer::GetItemFromContainer<MyClass, vector<MyClass>(myVector);

or

MyClass myClass = Fobaizer::GetItemFromContainer<MyClass, deque<MyClass>(myDeque);

Here C is any container like std::deque or std::vector. I search for a C98 solution without any lib (boost, QT, etc.)

In fact, I am looking for something like the IEnumerable of C#.

Any idea ?

Thank you.

È stato utile?

Soluzione

template <typename C>
static typename C::value_type GetItemFromContainer(const C & container) {
    typename C::value_type item = container[0]; // do something. 0 or iterator
    return item;
 }

Basically every container defines the member typedefs:

 value_type
 reference
 const_reference
 iterator
 const_iterator

So you can just use C::value_type if you want to return by value, C::reference if you want to return by reference, etc.

Altri suggerimenti

What I would do is create a test that checks whether you can call std::begin and std::end on your container. And then use iterators to those containers and std::advance to advance your iterators to where you need them.

The advantage of this method is then you can accept containers that don't overload operator[] (like std::list for example)

    #include <utility>
    #include <type_traits>
    #include <vector>
    #include <list>

    namespace sfinae_true_details
    {
        template <class>
        struct sfinae_true : std::true_type{};
    }

    template <class T>
    auto test_has_begin_end(int) ->
        sfinae_true_details::sfinae_true<decltype(std::begin(std::declval<T>()) ==
                                                  std::end(std::declval<T>())>;        

    template <class>
    std::false_type test_has_begin_end(long);

    template <class T>
    struct has_begin_end : decltype(test_has_begin_end<T>(0)){};

    int main()
    {
        static_assert(has_begin_end<std::vector<int> >::value, "");
        static_assert(has_begin_end<std::list<float> >::value, "");
        static_assert(has_begin_end<int>::value, "Expected to fail here");
        return 0;
    }

Then your usage would be:

      template <typename T, typename C>
      static T GetItemFromContainer(const C &container) {
          static_assert(has_begin_end<C>::value, "Must pass a container for which "
                        "std::begin and std::end are callable");
          T item = *std::begin(container); // do something. 0 or iterator
          auto iter = std::begin(container);
          std::advance(iter, 5);
          item = *iter; // equivalent to container[5] for RandomAccessContainers
          return item;
      }

Why you want to do IEnumerable in C++, iterator is a good choice to iterate a collection.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top