4

I am trying to use {fmt} to print a std::vector or std::array like this:

std::vector<double> vec = {1., 2., 3.};
fmt::print("{:0.3f}\n", fmt::join(vec, ","));

Thing is, I hope to print a transformed vector:

std::vector<double> vec = {1., 2., 3.};
std::vector<double> vec_dup;
std::transform(vec.begin(), vec.end(), std::back_inserter(vec_dup), [](auto x){return x * M_PI;});
fmt::print("{:0.3f}\n", fmt::join(vec_dup, ","));

Is there a way to do this in C++17 without the need to create a new container?

vvv444
  • 2,764
  • 1
  • 14
  • 25
auzn
  • 613
  • 3
  • 14

1 Answers1

2

Let's first see how in C++20 it can be easily achieved using the standard <ranges> library (Godbolt):

    std::vector<double> vec = {1., 2., 3.};

    auto func = [](auto x){ return x * M_PI; };
    auto&& new_range = vec | std::views::transform(func);
    
    fmt::print("{:0.3f}\n", fmt::join(new_range, ","));

If you are limited to C++17 you have two options:

  1. Use the 3rd party ranges-v3 library implementing the same functionality. For it, just replace in the above code:

    #include <range>       --> <range/v3/view/transform.hpp>
    std::views::transform  --> ranges::views::transform
    

    Godbolt demonstrating this.

  2. Implement such a generator class yourself. The class should get the source range and generator function as parameters, implement begin() and end() functions returning a helper iterator class. The helper iterator class should keep iterator to the underlying range, and call the generator function on de-reference.

vvv444
  • 2,764
  • 1
  • 14
  • 25
  • @auzn Is this helpful and gives you a satisfying solution? – vvv444 Apr 25 '23 at 07:01
  • It is indeed helpful. Thanks!. With {fmt} and ranges-v3, we are seriously thinking about simply switching to c++20... – auzn Apr 27 '23 at 07:38
  • @auzn Well, C++20 has many other advantages as well :-) Anyway, if this answers your question, please consider marking it as "accepted". – vvv444 Apr 27 '23 at 07:52