我怎样才能用容器模板?

时间:2014-04-01 12:05:02

标签: c++ templates containers

我不认为我的标题是准确的,所以只需转到代码。

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

示例:

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

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

此处C是std::dequestd::vector之类的任何容器。我在没有任何lib(boost,QT等)的情况下搜索C98解决方案

事实上,我正在寻找类似C#的IEnumerable

有什么想法吗?

谢谢。

3 个答案:

答案 0 :(得分:5)

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;
 }

基本上每个容器都定义了成员typedef:

 value_type
 reference
 const_reference
 iterator
 const_iterator

因此,如果您希望按值返回C::value_type,可以使用C::reference,如果您想通过引用返回,等等。

答案 1 :(得分:1)

我要做的是创建一个测试,检查您是否可以在容器上调用std::beginstd::end。然后使用迭代器到那些容器和std::advance来将迭代器推进到你需要的位置。

此方法的优点是您可以接受不会超载operator[]的容器(例如std::list

    #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;
    }

然后你的用法是:

      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;
      }

答案 2 :(得分:0)

为什么要在C ++中使用IEnumerable,迭代器是迭代集合的好选择。