Объединить несколько векторов (результаты функции) в один с шаблоном - PullRequest
5 голосов
/ 07 мая 2019

Я хотел бы иметь шаблонную функцию, принимающую vector<T> v и функцию op, отображающую T в vector<U>, и хотел бы объединить результаты применения f к каждому вектору элемента v чтобы вернуть vector<U> = [Элементы op (v [0]), Элементы op (v [1]) ...].

Я нашел вариант работы, добавив в функцию пример, позволяющий вычесть шаблон:

template <typename Container>
Container& concat(Container& c1, Container const& c2) {
  c1.insert(end(c1), begin(c2), end(c2));
  return c1;
}

template <typename Container, typename UnaryOperation, typename U>
inline auto to_vec_from_vectors(Container& c, UnaryOperation&& op, U& ex)
    -> std::vector<U> {
  std::vector<U> v;
  for (auto& e : c) {
    std::vector<U> opv = op(e);
    concat(v, opv);
  }
  return v;  
}

Но, естественно, я хотел бы получить тот же результат только с двумя параметрами. Моя попытка [заменить U на decltype(*std::begin(op(*std::begin(c))))]:

template <typename Container, typename UnaryOperation, typename U>
inline auto to_vec_from_vectors(Container& c, UnaryOperation&& op, U& ex)
    -> std::vector<decltype(*std::begin(op(*std::begin(c))))> {
  std::vector<decltype(*std::begin(op(*std::begin(c))))> v;
  for (auto& e : c) {
    std::vector<decltype(*std::begin(op(*std::begin(c))))> opv = op(e);
    concat(v, opv);
  }
  return v;  
}

К сожалению, это не скомпилировано. Я также беспокоюсь о том, чтобы тратить время, если операционная система сложная.

Это дало:

error: conversion from ‘std::vector<U>’ to non-scalar type ‘std::vector<const U&, std::allocator<const U&> >’ requested

error: forming pointer to reference type ‘const U&

... так что, похоже, это связано с «const».

Как бы исправить этот вариант? Есть ли лучшие альтернативы?

1 Ответ

5 голосов
/ 07 мая 2019

Разыменование контейнера-итератора дает ссылку (или ссылку на const, если контейнер был const), поэтому decltype(*std::begin(op(*std::begin(c)))) возвращает const U& в соответствии с ошибкой вашего компилятора (а не U).

Это можно исправить, либо снова удалив ссылку с помощью std :: remove_reference (или, если вы также хотите удалить const и volatile, std :: remove_cvref ) или просто спросив вектор, что он на самом деле хранит:

decltype(*std::begin(op(*std::begin(c)))) -> typename decltype(op(*std::begin(c)))::value_type

Я пошел дальше и удалил ненужный параметр U& ex.

template <typename Container, typename UnaryOperation>
inline auto to_vec_from_vectors(Container& c, UnaryOperation&& op)
    -> std::vector<typename decltype(op(*std::begin(c)))::value_type> {
  std::vector<typename decltype(op(*std::begin(c)))::value_type> v;
  for (auto& e : c) {
    std::vector<typename decltype(op(*std::begin(c)))::value_type> opv = op(e);
    concat(v, opv);
  }
  return v;  
}

Демо

Вы также можете избежать тройного повторения пения decltype, назвав его:

template <typename Container, typename UnaryOperation>
using applied_op_t = typename decltype(std::declval<UnaryOperation>()(*std::begin(std::declval<Container>())))::value_type;
...