2015-11-05 2 views
1

Я смотрю на генераторы лямбда от 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 иначе. Это должно работать одинаково. Что Вы думаете об этом?

+0

Использование boost :: optional. –

+0

, который отлично выглядит, но в зависимости от повышения не является вариантом для небольшого проекта, для которого это необходимо. –

+0

Вы можете попробовать std :: experimental :: optional, если ваш компилятор поддерживает его. –

ответ

0

Как только это выглядит как пример для изучения, я мог бы предложить добавить исключение в качестве конца коллекции. Но не используйте его в реальном коде.

Смежные вопросы