Floating point format for std::ostream

Viewed 77207

How do I do the following with std::cout?

double my_double = 42.0;
char str[12];
printf_s("%11.6lf", my_double); // Prints " 42.000000"

I am just about ready to give up and use sprintf_s.

More generally, where can I find a reference on std::ostream formatting that lists everything in one place, rather than spreading it all out in a long tutorial?

EDIT Dec 21, 2017 - See my answer below. It uses features that were not available when I asked this question in 2012.

8 Answers

In C++20 you'll be able to do

double my_double = 42.0;
char str[12];
std::format_to_n(str, sizeof(str), "{:11.6}", my_double); 

or

std::string s = std::format("{:11.6}", my_double); 

In the meantime you can use the {fmt} library that provides an implementation of format_to_n.

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

For future visitors who prefer actual printf-style format specs with std::ostream, here is yet another variation, based on Martin York's excellent post in another SO question: https://stackoverflow.com/a/535636:

#include <iostream>
#include <iomanip>
#include <stdio.h> //snprintf

class FMT
{
public:
    explicit FMT(const char* fmt): m_fmt(fmt) {}
private:
    class fmter //actual worker class
    {
    public:
        explicit fmter(std::ostream& strm, const FMT& fmt): m_strm(strm), m_fmt(fmt.m_fmt) {}
//output next object (any type) to stream:
        template<typename TYPE>
        std::ostream& operator<<(const TYPE& value)
        {
//            return m_strm << "FMT(" << m_fmt << "," << value << ")";
            char buf[40]; //enlarge as needed
            snprintf(buf, sizeof(buf), m_fmt, value);
            return m_strm << buf;
        }
    private:
        std::ostream& m_strm;
        const char* m_fmt;
    };
    const char* m_fmt; //save fmt string for inner class
//kludge: return derived stream to allow operator overloading:
    friend FMT::fmter operator<<(std::ostream& strm, const FMT& fmt)
    {
        return FMT::fmter(strm, fmt);
    }
};

usage example:

double my_double = 42.0;
cout << FMT("%11.6f") << my_double << "more stuff\n";

or even:

int val = 42;
cout << val << " in hex is " << FMT(" 0x%x") << val << "\n";

Some great answers already; kudos to those!

This is based on some of them. I have added type assertions for POD types, since they are the only safe types usable with printf().

#include <iostream>
#include <stdio.h>
#include <type_traits>

namespace fmt {
namespace detail {

template<typename T>
struct printf_impl
{
    const char* fmt;
    const T v;

    printf_impl(const char* fmt, const T& v) : fmt(fmt), v(v) {}
};

template<typename T>
inline typename std::enable_if<std::is_pod<T>::value, std::ostream& >::type
operator<<(std::ostream& os, const printf_impl<T>& p)
{
    char buf[40];
    ::snprintf(buf, sizeof(buf), p.fmt, p.v, 40);
    return os << buf;
}

} // namespace detail

template<typename T>
inline typename std::enable_if<std::is_pod<T>::value, detail::printf_impl<T> >::type
printf(const char* fmt, const T& v)
{
    return detail::printf_impl<T>(fmt, v);
}

} // namespace fmt

Example usage it as below.

std::cout << fmt::printf("%11.6f", my_double);

Give it a try on Coliru.

Related