Каков наилучший способ взять в общем случае контейнер в C ++ с использованием интерфейсов (то есть эквивалент принятия IEnumerable в качестве аргумента в C #) - PullRequest
2 голосов
/ 17 декабря 2009

Я бы хотел, чтобы конструктор / метод C ++ мог принимать любой контейнер в качестве аргумента. В C # это было бы легко с помощью IEnumerable, есть ли эквивалент в C ++ / STL?

Anthony

Ответы [ 3 ]

6 голосов
/ 17 декабря 2009

C ++ способ сделать это с помощью итераторов. Как и все функции <algorithm>, которые принимают (it begin, it end, ) в качестве первых двух параметров.

template <class IT>
T foo(IT first, IT last)
{
    return std::accumulate(first, last, T());
}

Если вы действительно хотите передать сам контейнер функции, вы должны использовать параметры шаблона шаблона. Это связано с тем, что контейнеры стандартной библиотеки C ++ не только шаблонируются с типом содержимого типа, но также и с типом распределителя, который имеет значение по умолчанию и поэтому является неявным и не известен.

#include <vector>
#include <list>
#include <numeric>
#include <iostream>

template <class T, class A, template <class T, class A> class CONT>
T foo(CONT<T, A> &cont)
{
    return std::accumulate(cont.begin(), cont.end(), T());
}

int main()
{
    std::vector<int> v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);

    std::list<int> l;
    l.push_back(1);
    l.push_back(2);
    l.push_back(3);

    std::cout << foo(v) << " " << foo(l) << "\n";

    return 0;
}
1 голос
/ 23 января 2011

Хороший вопрос, +1. Как жаль, ему два года ... В любом случае, я отправляю ответ: вы застряли на "C ++ way", если хотите только открыть интерфейс своей библиотеки. Мой способ сделать это так:

template<class TValue>
class IEnumerator {
 public:
  virtual bool MoveNext() = 0;
  vírtual TValue Current() = 0;
  virtual void Reset() = 0;
};

template<class TValue>
class IEnumerable {
 public:
  virtual std::unique_ptr< IEnumerator<TValue> > GetEnumerator() const = 0;
};

Таким образом, вы можете написать API следующего вида:

void MyAPI(const IEnumerable<IMyLibAPIObject>& pSequence);

Конечно, я предоставляю различные реализации, такие как StlEnumerator или StlEnumerable, или EnumeratorAdaptor<T, U>, чтобы получить ковариацию, как в C # ...

Приветствия

Пол

Редактировать: До сих пор у меня был тип, удаляющий AnyEnumerator и AnyEnumerable. Также мне известно о различных реализациях any_iterator ...

1 голос
/ 17 декабря 2009

Зависит от того, что вы хотите сделать с контейнером. Одна мысль: просто передайте итератор, если вы хотите получить доступ к тому, что хранится в контейнере.

...