Подтвердить что ты не робот

Может повысить: algorithm:: join() concat контейнер с поплавками?

Boost join может использоваться для конкатенации контейнера строк, необязательно разделенных строкой разделителя, как показано в этом примере: Хороший пример для boost:: algorithm:: join

Мои навыки STL слабы. Мне интересно, можно ли использовать одну и ту же функцию для контейнера чисел (float, double, ints)? Кажется, что один или два слоя нужно адаптировать для других типов.

Существует также функция копирования stl с хорошим примером, который можно найти здесь: Как распечатать содержимое вектора?

Но мне не нравится, как он добавляет строку разделителя после каждого элемента. Я хотел бы просто использовать boost.

4b9b3361

Ответ 1

Конечно, вы можете комбинировать boost::algorithm::join и boost::adaptors::transformed, чтобы преобразовать двойники в строки и затем объединить их.

#include <iostream>
#include <vector>
#include <string>

#include <boost/algorithm/string/join.hpp>
#include <boost/range/adaptor/transformed.hpp>

int main()
{
    using boost::adaptors::transformed;
    using boost::algorithm::join;

    std::vector<double> v{1.1, 2.2, 3.3, 4.4};

    std::cout 
      << join( v | 
               transformed( static_cast<std::string(*)(double)>(std::to_string) ), 
               ", " );
}

Вывод:

1.100000, 2.200000, 3.300000, 4.400000


Вы также можете использовать лямбда, чтобы избежать уродливого литья

join(v | transformed([](double d) { return std::to_string(d); }), ", ")

Ответ 2

Мои навыки STL слабы. Мне интересно, если в любом случае использовать одну и ту же функцию для контейнера чисел (float, double, ints)? Кажется, что нужно использовать один или два слоя для других типов.

std::accumulate позволяет выполнять сброс по любому (входному) диапазону итераторов, используя двоичную функцию, которая может принимать разные типы для "аккумулятора" и следующего элемента. В вашем случае: функция принимает std::string и a double (или что-то еще), которые объединяют данный std::string с результатом std::to_string по второму параметру.

template<typename Container>
std::string contents_as_string(Container const & c,
                               std::string const & separator) {
  if (c.size() == 0) return "";
  auto fold_operation = [&separator] (std::string const & accum,
                                      auto const & item) {
    return accum + separator + std::to_string(item);};
  return std::accumulate(std::next(std::begin(c)), std::end(c),
                         std::to_string(*std::begin(c)), fold_operation);
}

Как вы можете видеть, это полностью не зависит от типа значения контейнера. Пока вы можете передать его std::to_string, вы в порядке. На самом деле выше код представляет собой небольшое изменение пример, представленный для std::accumulate.

Демо выше функции:

int main() {
  std::vector<double> v(4);
  std::iota(std::begin(v), std::end(v), 0.1);
  std::cout << contents_as_string(v, ", ") << std::endl;

  std::vector<int> w(5);
  std::iota(std::begin(w), std::end(w), 1);
  std::cout << contents_as_string(w, " x ") << " = "
    << std::accumulate(std::begin(w), std::end(w), 1, std::multiplies<int>{})
    << std::endl;
}

0.100000, 1.100000, 2.100000, 3.100000
1 x 2 x 3 x 4 x 5 = 120