C++11 Equivalent to Boost.Format
Asked Answered
S

5

25

Anything like Boost.Format in the C++11 standard? I've been able to avoid using Boost with a better C++11 option for every other need I've had.

For that matter, Boost.Format doesn't hold a candle to the syntax of Python format(). Something like that would be even better.

Searby answered 1/5, 2014 at 17:26 Comment(3)
What's wrong with good old C/K&R xxprintf()?Haul
I like it in general but it can't accept string directly, which is annoying. I would prefer a method that doesn't require me to call .c_str() on all my strings. Plus, it is nowhere near as nice as the Python's format().Searby
@FoggyDay: No type safety. At all. Zero extensibility.Odontograph
A
7

There is a proposal for something similar to boost-format. However, it's neither part of C++11 nor C++14, nor has anything related to string formatting be added.

Here you can find the latest proposal. In contrast to boost-format, it's based on variadic templates.

Amusement answered 1/5, 2014 at 17:57 Comment(0)
F
32

C++11, 14 and 17 don't provide anything like that.

However, C++20 provides std::format which is similar in spirit to Boost Format but with the design permitting more efficient implementation. The {fmt} library is an implementation of this formatting facility and it only requires C++11:

std::string s = fmt::format("I'd rather be {1} than {0}.", "right", "happy");

Disclaimer: I'm the author of {fmt} and C++20 std::format

Fume answered 8/10, 2014 at 21:34 Comment(0)
A
7

There is a proposal for something similar to boost-format. However, it's neither part of C++11 nor C++14, nor has anything related to string formatting be added.

Here you can find the latest proposal. In contrast to boost-format, it's based on variadic templates.

Amusement answered 1/5, 2014 at 17:57 Comment(0)
I
2

Python-like format string function implementation with c++11 regex and variadic templates.

/**
   Helper code to unpack variadic arguments
*/
namespace internal
{
    template<typename T>
    void unpack(std::vector<std::string> &vbuf, T t)
    {
        std::stringstream buf;
        buf << t;
        vbuf.push_back(buf.str());
    }
    template<typename T, typename ...Args>
    void unpack(std::vector<std::string> &vbuf, T t, Args &&... args)
    {
        std::stringstream buf;
        buf << t;
        vbuf.push_back(buf.str());
        unpack(vbuf, std::forward<Args>(args)...);
    }
}

/**
    Python-like string formatting
 */
template<typename ... Args>
std::string format(const std::string& fmt, Args ... args)
{
    std::vector<std::string> vbuf;  // store arguments as strings
    std::string in(fmt), out;    // unformatted and formatted strings
    std::regex re_arg("\\{\\b\\d+\\b\\}");  // search for {0}, {1}, ...
    std::regex re_idx("\\b\\d+\\b");        // search for 0, 1, ...
    std::smatch m_arg, m_idx;               // store matches
    size_t idx = 0;                         // index of argument inside {...}

    // Unpack arguments and store them in vbuf
    internal::unpack(vbuf, std::forward<Args>(args)...);

    // Replace all {x} with vbuf[x]
    while (std::regex_search(in, m_arg, re_arg)) {
        out += m_arg.prefix();
        auto text = m_arg[0].str();
        if (std::regex_search(text, m_idx, re_idx)) {
            idx = std::stoi(m_idx[0].str());
        }
        if(idx < vbuf.size()) {
            out += std::regex_replace(m_arg[0].str(), re_arg, vbuf[idx]);
        }
        in = m_arg.suffix();
    }
    out += in;
    return out;
}

Example: cpp.sh/9cvtz

Interment answered 17/6, 2017 at 18:50 Comment(5)
when I include the templates by a header and call format with C++11, I get an "use of deleted function"-error. Could you give me some help, please?Pasture
Sure, could you provide a snippet that reproduces the error?Interment
i will formulate a question on so tomorrow and link to it. But anyway: to produce this error, just put the 2 templates in an header file and include it in main. This should be sufficient. But I will check tomorrow in detail.Pasture
ok, when working on a minimal example, it turned out, the code is not even compiling in other online compilers nor in g++. Here is an example: onlinegdb.com/rJNMvHDNvPasture
I see, regex_search is no longer permits temporary strings, so add this: auto tmp = m_arg[0].str(); before calling regex_search and pass tmp as a first argument.Interment
P
0

using sprintf

  • For C++20, use std::format
  • there is the fmt-library from version C++11 on
  • some simple solution for formated output is printf
  • to use printf syntax to write a std::string, use the following snippet

minimal reproducible example: format std::string with printf syntax

interactive version

#include <iostream>
#include <string>
#include <stdio.h>
#include <assert.h>


template<typename... Args>
std::string fmt_str(std::string fmt, Args... args)
{
    size_t bufferSize = 1000;
    char *buffer = new char[bufferSize];
    int n = sprintf(buffer, fmt.c_str(), args...);
    assert (n >= 0 and n < (int) bufferSize - 1  && "check fmt_str output");

    std::string fmtStr (buffer);
    delete buffer;
    return fmtStr;
}



int main()
{
    int a=1, b=2;
    double c=3.;
    std::cout << fmt_str("%d plus %d is %f", a, b, c) << std::endl;
    return 0;
}

output

1 plus 2 is 3.000000
Pasture answered 10/9, 2020 at 7:23 Comment(0)
R
0
template<typename... Args>
std::string fmt_str(const std::string& fmt, Args... args)
{
    static const int bufferSize = 1000;
    char buffer[bufferSize];
    int n = snprintf(buffer, bufferSize, fmt.c_str(), args...);
    assert(n >= 0 and n <= bufferSize - 1 && "check fmt_str output");

    return (buffer);
}

//Based on Markus, a little improvements: input change to ref, buffer avoid new, use snprintf to avoid buffer overflow, return directly to avoid copy constructor. Using it in my project

//It should be a comment to Markus Dutschke's, not an answer, but the comment field can't format a code piece well, and I extract the code here.

Resourceful answered 10/1, 2023 at 4:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.