How do I print a vector of chars using fmt?
Asked Answered
D

3

5

I have a const std::vector<char> - not null-terminated. I want to print it using the fmt library, without making a copy of the vector.

I would have hoped that specifying the precision would suffice, but the fmt documentation says that :

Note that a C string must be null-terminated even if precision is specified.

Well, mine isn't. Must I make a copy and pad it with \0, or is there something else I can do?

Demibastion answered 5/6, 2022 at 20:18 Comment(6)
Well, that's what it says, and no alternatives are mentioned, so that's the only option.Marvismarwin
@SamVarshavchik: But maybe fmt has some magical sequence printing capability?Demibastion
You are aware of cout << in a loop? #10750557Og
Do you want to interpret it as a string? If so, you could always just make a string_view and use that.Kob
@IlCapitano: So, I'm actually not in C++20 for this, but that would work, yes.Demibastion
@tevemadar: For reasons, I can't work with an ostream.Demibastion
D
2

tl;dr: std::cout << fmt::format("{}", fmt::string_view{v.data(), v.size()});


So, fmt accepts two kinds of "strings":

  • C-style - just a pointer, must be null-terminated.
  • std::string-like - data + length.

Since C++17, C++ officially has the reference-type, std::string-like string view class, which could refer to your vector-of-chars. (without copying anything) - and fmt can print these. Problem is, you may not be in C++17. But fmt itself also has to face this problem internally, so it's actually got you covered - in whatever version of the standard you can get fmt itself to compile, in particular C++14:

const std::vector<char> v;
fmt::string_view sv(v.data(), v.size());
auto str = fmt::format("{}", sv);
std::cout << str;

Thanks @eerorika for making me think of string views.

Demibastion answered 5/6, 2022 at 20:36 Comment(2)
That's really neat.Panay
@vitaut: Indeed, I had thought it might not be available before C++17, but it turns out it is.Demibastion
T
8

If you could upgrade to C++17, then you could use a strig view argument instead of pointer to char:

const std::vector<char> v;
std::string_view sv(v.data(), v.size());
fmt::format("{}", sv);
Tropical answered 5/6, 2022 at 20:28 Comment(0)
S
5

What about using fmt::join?

Returns a view that formats range with elements separated by sep.

[Demo]

#include <fmt/ranges.h>
#include <vector>

int main() {
    std::vector<char> v{'a', 'b', 'c'};
    fmt::print("{}", fmt::join(v, ""));
}

// Outputs:
//
//   abc
Striated answered 5/6, 2022 at 23:15 Comment(1)
It might be a little over the top for a very large vector, but yeah, definitely. +1.Demibastion
D
2

tl;dr: std::cout << fmt::format("{}", fmt::string_view{v.data(), v.size()});


So, fmt accepts two kinds of "strings":

  • C-style - just a pointer, must be null-terminated.
  • std::string-like - data + length.

Since C++17, C++ officially has the reference-type, std::string-like string view class, which could refer to your vector-of-chars. (without copying anything) - and fmt can print these. Problem is, you may not be in C++17. But fmt itself also has to face this problem internally, so it's actually got you covered - in whatever version of the standard you can get fmt itself to compile, in particular C++14:

const std::vector<char> v;
fmt::string_view sv(v.data(), v.size());
auto str = fmt::format("{}", sv);
std::cout << str;

Thanks @eerorika for making me think of string views.

Demibastion answered 5/6, 2022 at 20:36 Comment(2)
That's really neat.Panay
@vitaut: Indeed, I had thought it might not be available before C++17, but it turns out it is.Demibastion

© 2022 - 2024 — McMap. All rights reserved.