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

Question: locale treated differently by fmt and std::cout #3460

Closed
mcharneyamp opened this issue May 24, 2023 · 4 comments
Closed

Question: locale treated differently by fmt and std::cout #3460

mcharneyamp opened this issue May 24, 2023 · 4 comments

Comments

@mcharneyamp
Copy link

Pretty sure this is me being stupid; not a bug. Please see example here:

https://godbolt.org/z/rasnKzfae

When I uncomment line 22, I get what I want: no commas in hex number.

When I comment out line 22, I get commas in my hex numbers which is not what anyone would want.

What's the right way to do not get commas in hex numbers when using fmt and overloaded ostream operators?

Seems like std::out does not "see" the locale in the way fmt does. Is this because std::cout is constructed before main() sets std::locale::global(std::locale("en_US.UTF-8"));?

Thank you for your help. Apologies if this is a stupid question.

#include <cstdint>
#include <locale>
#include <ostream>
#include <iostream>
#include <iomanip>
#include <fmt/core.h>
#include <fmt/ostream.h>

class Foo {
public:
    Foo() = default;
    explicit Foo(std::uint64_t value) : contents(value) {}
    Foo(const Foo& other) : contents(other.contents) {}
    std::uint64_t value() const { return contents; }
    friend std::ostream& operator<<(std::ostream& os, const Foo& addr);
    std::uint64_t contents{0};
};

template <> struct fmt::formatter<Foo> : ostream_formatter {};
std::ostream& operator<<(std::ostream& os, const Foo& addr) {
    auto old_locale = os.getloc();
    os.imbue(std::locale("C"));  // line 22. comment this out and we get commas in hex number
    auto flags = os.setf(std::ios::hex, std::ios::basefield);
    os << addr.value();
    os.setf(flags);
    os.imbue(old_locale);
    return os;
}

int main(int argc, char** argv) {
    std::locale::global(std::locale("en_US.UTF-8"));
    Foo x(0xABCDEF00F);
    std::cout << "std cout: " << x << "\n";
    fmt::print("fmt     : {}\n", x);
}
@vitaut
Copy link
Contributor

vitaut commented May 24, 2023

Currently ostream_formatter uses the locale passed into a formatting function (or global locale if there is none) but I think it's reasonable to switch the default to classic locale in

if (loc) output.imbue(loc.get<std::locale>());

It will be more consistent with other defaults which are locale-independent.

A PR is welcome!

@mcharneyamp
Copy link
Author

Thanks, Victor!

@vitaut vitaut changed the title Question: locale treated differently by fmt and std::out Question: locale treated differently by fmt and std::cout Sep 18, 2023
@vitaut
Copy link
Contributor

vitaut commented Nov 24, 2023

Fixed in 8a39388.

@mcharneyamp
Copy link
Author

Thanks, Victor!

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