Защищенная итерация через пользовательский контейнер

Я хочу сделать контейнерный класс, который должен быть разрешен для итерации для каждого цикла, но только для каждого цикла. Я не хочу предоставлять доступ к его методам .begin () и .end ().

Возможна ли такая вещь, может быть, через перегрузку и дружбу методов std :: begin и std :: end?

Я сделал несколько попыток, одна из которых выглядит примерно так: Однако компилятор всегда жаловался на конфиденциальность .begin () и .end ().

namespace std {

MyIter begin (MySealedContainer&);
MyIter end (MySealedContainer&);

}

class MyIter {
// ...
};

class MySealedContainer {
friend MyIter std::begin (MySealedContainer&);
friend MyIter std::end (MySealedContainer&);

private:
MyIter begin();
MyIter end();

// ...
};

// ---

MyIter std::begin (MySealedContainer& c) {
return c.begin();
}

MyIter std::end (MySealedContainer& c) {
return c.end();
}

Даже с частными .begin () и .end () я должен быть в состоянии сделать следующее:

MySealedContainer foo;
// Insert elements...

for (auto& each: foo) {
// Do something with each.
}

0

Решение

Используя дружбу, чтобы предоставить доступ к std::begin а также std::end не предоставит никаких преимуществ. Другой код будет свободно использовать их для получения доступа к адаптерам итераторов, что делает весь подход бесполезным. В конце концов это заканчивается как MySpace, и никто не хочет больше его использовать. В конце концов вы в конечном итоге, как Facebook, все злоупотребляют им и делают то, что вы от них не хотите.

Единственный вариант обработки начала / конца — предоставить доступ к отдельным классам и свободным функциям через дружбу. К сожалению, это наложит ограничения на его использование и потребует обновления каждый раз, когда вы хотите предоставить доступ к дополнительным функциям. В следующем примере подчеркивается бесполезность использования дружбы для предоставления доступа к бесплатной функции, такой как std::begin

class Restricted
{
int begin() { return 0; }

friend int std_begin(Restricted&r);
};

int std_begin(Restricted&r)
{
return r.begin();
}int main()
{
Restricted  building;

// Side step private! might as well just call building.begin()
int it = std_begin(building);
}
[Старый ненужный ответ оставлен для исторической незначительности]

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

#include <iostream>
#include <vector>

class Adapter
{
public:

template<typename FuncType>
void for_each(FuncType &func)
{
for(std::vector<int>::iterator it = data_.begin();
it != data_.end();
++it)
{
// Pass by value (prevent modification)
// you can pass the iterator as is if you like!
func(*it);
}
}
//private: we leave it public for demo purposes
std::vector<int>    data_;
};

int main()
{
Adapter cnt;

cnt.data_.push_back(1);
cnt.data_.push_back(2);
cnt.data_.push_back(3);
cnt.data_.push_back(4);

struct {
void operator()(int value) {
std::cout << value << std::endl;
}
} for_function;

cnt.for_each(for_function);
}

Вы хотите добавить const квалифицированных версий for_each Функциональные и возможные несколько перегрузок с различным количеством параметров в зависимости от ваших требований. С C ++ 11 у вас есть возможность передать лямбда или использовать std::function и вы также можете использовать компоненты, включенные в Boost.

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]