Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: support %s with numeric arguments #360

Closed
avikivity opened this issue Jul 18, 2016 · 3 comments
Closed

Feature request: support %s with numeric arguments #360

avikivity opened this issue Jul 18, 2016 · 3 comments

Comments

@avikivity
Copy link

We're (seastar, scylla) switching from boost::format to libfmt; but many of our format strings have %s for numeric arguments; this is handled by boost.

Could fmtlib be changed to tolerate %s for numeric arguments?

@vitaut
Copy link
Contributor

vitaut commented Jul 19, 2016

Thanks for using the library!

It is possible to make fmt::printf and friends accept %s for numeric arguments, but I'd rather not diverge from std::printf too much unless there are strong reasons to do so. However, it is easy to define a custom printf argument formatter that implements the desired behavior:

#include "fmt/printf.h"

// A custom argument formatter that allows %s for integer values.
class CustomPrintfArgFormatter :
  public fmt::internal::BasicPrintfArgFormatter<CustomPrintfArgFormatter, char> {
public:
  typedef fmt::internal::BasicPrintfArgFormatter<CustomPrintfArgFormatter, char> Base;

  CustomPrintfArgFormatter(fmt::BasicWriter<char> &w, fmt::FormatSpec &s) : Base(w, s) {}

  template <typename T>
  void visit_any_int(T value) {
    if (this->spec().type_ == 's')
      this->spec().type_ = 'd';
    Base::visit_any_int(value); // The same can be done for floating-point values.
  }
};

FMT_FUNC int custom_printf(fmt::CStringRef format, fmt::ArgList args) {
  fmt::MemoryWriter w;
  fmt::internal::PrintfFormatter<char, CustomPrintfArgFormatter>(args).format(w, format);
  std::size_t size = w.size();
  return std::fwrite(w.data(), 1, size, stdout) < size ? -1 : static_cast<int>(size);
}
FMT_VARIADIC(int, custom_printf, fmt::CStringRef)

int main() {
  custom_printf("%s", 42); // Prints 42 instead of throwing an exception.
}

Currently this relies on internal APIs, but I can make them public. Will it work for you?

@avikivity
Copy link
Author

avikivity commented Jul 19, 2016

Yes, it will. Perhaps an easier alternative for people migrating from boost is to have a variant compatible with boost::format, accessible via a different name.

(we had a very east migration because you boost::format calls were wrapped in a variadic function that generated the silly fmt % arg % arg syntax, and the only thing missing was %s for numbers, which I added as a local patch)

@vitaut
Copy link
Contributor

vitaut commented Jul 21, 2016

PrintfFormatter and BasicPrintfArgFormatter are now public and documented in http://fmtlib.net/dev/api.html#_CPPv2N3fmt15PrintfFormatterE.

I'd be happy to accept a custom formatter that implements Boost Format compatibility if anyone is interested in contributing it. Unfortunately I don't have time to work on it myself.

@vitaut vitaut closed this as completed Jul 21, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants