Я смотрю на генераторы лямбда от https://stackoverflow.com/a/12735970 и https://stackoverflow.com/a/12639820. Я хотел бы адаптировать их к шаблонной версии, и мне интересно, что я должен вернуть, чтобы сообщить, что генератор достиг своего конца.C++ 11 Lambda Generator - Как сигнализировать последний элемент или конец?
Рассмотрим
template<typename T>
std::function<T()> my_template_vector_generator(std::vector<T> &v) {
int idx = 0;
return [=,&v]() mutable {
return v[idx++];
};
}
[=,&v]
дополнение моя, и я надеюсь, что это правильно. Пока, это позволяет мне изменить вектор снаружи, как ожидалось. Просьба прокомментировать это, если у вас плохое чувство об этом ... Для справки, это работает (ТРЕБУЮТ от catch):
std::vector<double> v({1.0, 2.0, 3.0});
auto vec_gen = my_template_vector_generator(v);
REQUIRE(vec_gen() == 1);
REQUIRE(vec_gen() == 2);
v[2] = 5.0;
REQUIRE(vec_gen() == 5.0);
Этого вектор версия, очевидно, требует знаний v.size()
на месте вызова. Я бы хотел пойти без этого, возвращая что-то, что указывает на то, что генератор пуст.
Мозговой, я могу думать о следующем:
- возвращение
pair<T, bool>
и указатьfalse
раз нет больше значений. - возвращает итераторы к значениям контейнера и итерации
for (auto it=gen(); it!=gen.end(); it=gen()) {cout << *it << endl;}
- обертывание генератора в классе и внедрение метода
empty()
. Однако не совсем уверен, как это будет работать.
Может ли любая из этих версий чувствовать себя хорошо? У вас есть другая идея? Мне особенно интересны последствия при сопоставлении такого генератора или их рекурсивном объединении (см. Это C++14 blog post for inspiration).
Обновление: После прослушивания дополнительных предложений я внедрил что-то на основе unique_ptr.
template<typename T>
std::function<std::unique_ptr<T>()> my_pointer_template_vector_generator(std::vector<T> &v) {
int idx = 0;
return [=,&v]() mutable {
if (idx < v.size()) {
return std::unique_ptr<T>(new T(v[idx++]));
} else {
return std::unique_ptr<T>();
}
};
}
Это, кажется, работает, рассмотрите следующий проходной тест.
TEST_CASE("Pointer generator terminates as expected") {
std::vector<double> v({1.0, 2.0, 3.0});
int k = 0;
auto gen = my_pointer_template_vector_generator(v);
while(auto val = gen()) {
REQUIRE(*val == v[k++]);
}
REQUIRE(v.size() == k);
}
У меня есть некоторые опасения по поводу создания множества новых T. Я полагаю, я мог бы также возвращать указатели в вектор и nullptr иначе. Это должно работать одинаково. Что Вы думаете об этом?
Использование boost :: optional. –
, который отлично выглядит, но в зависимости от повышения не является вариантом для небольшого проекта, для которого это необходимо. –
Вы можете попробовать std :: experimental :: optional, если ваш компилятор поддерживает его. –