Я хочу сделать контейнерный класс, который должен быть разрешен для итерации для каждого цикла, но только для каждого цикла. Я не хочу предоставлять доступ к его методам .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.
}
Используя дружбу, чтобы предоставить доступ к 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.
Других решений пока нет …