I'm trying to format a boost multiprecision cpp_int using fmt library.
Here's the code I tried
using boost::multiprecision::cpp_int;
int main() {
cpp_int v("0x8FFFFFFFFFFFFFFFF");
std::string buffer;
fmt::format_to(std::back_inserter(buffer),"{}", v);
std::cout << buffer;
}
https://godbolt.org/z/M4zKc5hr6
using boost 1.73, fmt 9.1, gcc 7.3
I'm getting compilation error:
error: static assertion failed: Cannot format an argument. To make type T formattable provide a formatter specialization
I stumbled upon this issue https://github.com/fmtlib/fmt/issues/918 that seems to be resolved, so I was expecting fmt to be able to format boost multiprecision numbers. Do I still need to write a formatter specialization?
You need to provide a formatter. E.g. you can opt-in to the ostream formatter:
template <> struct fmt::formatter<cpp_int> : fmt::ostream_formatter {};
Live demo: Live On Coliru
#include <boost/multiprecision/cpp_int.hpp>
#include <fmt/format.h>
#include <fmt/ostream.h>
using boost::multiprecision::cpp_int;
template <> struct fmt::formatter<cpp_int> : fmt::ostream_formatter {};
int main() {
cpp_int v("0x8FFFFFFFFFFFFFFFF");
std::string buffer;
fmt::format_to(std::back_inserter(buffer), "Hello world: {}", v);
fmt::print("Print directly: {} (buffer: {})", v, buffer);
}
Outputs:
Print directly: 166020696663385964543 (buffer: Hello world: 166020696663385964543)
BONUS: Hex, showbase, lower/uppercase
Demonstrating a simple custom formatter that invokes i.str(...) with the required formatting parameters:
Live On Coliru
#include <boost/multiprecision/cpp_int.hpp>
#include <fmt/format.h>
using boost::multiprecision::cpp_int;
template <> struct fmt::formatter<cpp_int> {
uint8_t showbase_ : 1 = 0, hex_ : 1 = 0, upper_ : 1 = 0;
auto constexpr parse(auto& ctx) {
auto e = std::find(ctx.begin(), ctx.end(), '}');
if (std::string_view f{ctx.begin(), e}; f == "#x")
showbase_ = hex_ = true;
else if (f == "#X")
showbase_ = hex_ = upper_ = true;
else {
hex_ = (f == "x") || (f == "X");
upper_ = (f == "X");
}
return e;
}
auto format(cpp_int const& i, auto& ctx) {
auto f = hex_ ? std::ios::hex : std::ios::dec;
if (showbase_) f |= std::ios::showbase;
if (upper_) f |= std::ios::uppercase;
auto s = i.str(0, f);
return std::copy(s.begin(), s.end(), ctx.out());
}
};
int main() {{
cpp_int v("0x8FFFFFFFFFFFFFFFF");
fmt::print("{{}}: {}\n", v);
fmt::print("{{:}}: {:}\n", v);
fmt::print("{{:x}}: {:x}\n", v);
fmt::print("{{:#x}}: {:#x}\n", v);
fmt::print("{{:X}}: {:X}\n", v);
fmt::print("{{:#X}}: {:#X}\n", v);
}}
Prints
{}: 166020696663385964543
{:}: 166020696663385964543
{:x}: 8ffffffffffffffff
{:#x}: 0x8ffffffffffffffff
{:X}: 8FFFFFFFFFFFFFFFF
{:#X}: 0X8FFFFFFFFFFFFFFFF
Related
In C++, how do I print the type contained in a variant at run time?
My use case: passing a dictionary of values from Python to C++ using pybind11, and I want to print out the types that are received.
You can get a generic solution with std::visit and some typename printing library, such as Boost.TypeIndex. An exemplary solution:
#include <iostream>
#include <type_traits>
#include <variant>
#include <boost/type_index.hpp>
int main()
{
std::variant<char, bool, int, double> v;
auto print_variant_type =
[](auto&& value)
{
using T = std::decay_t<decltype(value)>;
std::cout << boost::typeindex::type_id<T>().pretty_name() << std::endl;
};
v = 'a';
std::visit(print_variant_type, v); // prints out "char"
v = true;
std::visit(print_variant_type, v); // prints out "bool"
v = 1;
std::visit(print_variant_type, v); // prints out "int"
v = 1.0;
std::visit(print_variant_type, v); // prints out "double"
}
Live demo: https://godbolt.org/z/Web5zeGof
The only drawback is that it can print "ugly" type names for library types that are type aliases (such as std::string). An alternative for a particular variant instance, possibly more suitable for you, may be using a mapping from a variant index to type names:
using variant_type = std::variant<char, bool, int, double, std::string>;
static const std::array variant_type_names =
{ "char", "bool", "int", "double", "std::string" };
void print_variant_type(const variant_type& v)
{
assert(v.index() < variant_type_names.size());
std::cout << variant_type_names[v.index()] << std::endl;
}
int main()
{
variant_type v;
v = 'a';
print_variant_type(v); // prints out "char"
v = true;
print_variant_type(v); // prints out "bool"
v = 1;
print_variant_type(v); // prints out "int"
v = 1.0;
print_variant_type(v); // prints out "double"
v = std::string("some string");
print_variant_type(v); // prints out "std::string"
}
Live demo: https://godbolt.org/z/9na1qzEKs
You could use function overloading like so:
#include <iostream>
#include <variant>
using VariantT = std::variant<int, float>;
namespace {
std::string name(const float& ) {
return "float";
}
std::string name(const int& ) {
return "int";
}
std::string variantName(const VariantT& v) {
return std::visit(
[](const auto &v) { return name(v); },
v
);
}
}
int main() {
std::variant<int, float> v;
v = 1;
std::cout << variantName(v) << std::endl;
v = 1.f;
std::cout << variantName(v) << std::endl;
}
Tested under MSVC 2022 and C++17. Should work on gcc and clang but untested.
#include <string>
#include <variant>
#include <type_traits>
/**
* \brief Variant type to string.
* \tparam T Variant type.
* \param v Variant.
* \return Variant type as a string.
*/
template<typename T>
std::string variant_type_string(T v)
{
std::string result;
if constexpr(std::is_constructible_v<T, int>) { // Avoids compile error if variant does not contain this type.
if (std::holds_alternative<int>(v)) { // Runtime check of type that variant holds.
result = "int";
}
}
else if constexpr(std::is_constructible_v<T, std::string>) {
if (std::holds_alternative<std::string>(v)) {
result = "string";
}
}
else if constexpr(std::is_constructible_v<T, bool>) {
if (std::holds_alternative<bool>(v)) {
result = "bool";
}
}
else {
result = "?";
}
return result;
}
To use:
std::variant<int, std::string> v { 42 };
std::cout << variant_type_string(v);
// Prints: int
I am using Boost Spirit X3 to create a programming language, but when I try to support Unicode, I get an error!
Here is an example of a simplified version of that program.
#define BOOST_SPIRIT_X3_UNICODE
#include <boost/spirit/home/x3.hpp>
namespace x3 = boost::spirit::x3;
struct sample : x3::symbols<unsigned> {
sample()
{
add("48", 10);
}
};
int main()
{
const std::string s("🌸");
boost::u8_to_u32_iterator<std::string::const_iterator> first{cbegin(s)},
last{cend(s)};
x3::parse(first, last, sample{});
}
Live on wandbox
What should I do?
As you noticed, internally char_encoding::unicode employs char32_t.
So, first changing the symbols accordingly:
template <typename T>
using symbols = x3::symbols_parser<boost::spirit::char_encoding::unicode, T>;
struct sample : symbols<unsigned> {
sample() { add(U"48", 10); }
};
Now the code fails calling into case_compare:
/home/sehe/custom/boost_1_78_0/boost/spirit/home/x3/string/detail/tst.hpp|74 col 33| error: no match for call to ‘(boost::spirit::x3::case_compare<boost::spirit::char_encoding::unicode>) (reference, char32_t&)’
As you can see it expects a char32_t reference, but u8_to_u32_iterator returns unsigned ints (std::uint32_t).
Just for comparison / sanity check: https://godbolt.org/z/1zozxq96W
Luckily you can instruct the u8_to_u32_iterator to use another co-domain type:
Live On Compiler Explorer
#define BOOST_SPIRIT_X3_UNICODE
#include <boost/spirit/home/x3.hpp>
#include <iomanip>
#include <iostream>
namespace x3 = boost::spirit::x3;
template <typename T>
using symbols = x3::symbols_parser<boost::spirit::char_encoding::unicode, T>;
struct sample : symbols<unsigned> {
sample() { add(U"48", 10)(U"🌸", 11); }
};
int main() {
auto test = [](auto const& s) {
boost::u8_to_u32_iterator<decltype(cbegin(s)), char32_t> first{
cbegin(s)},
last{cend(s)};
unsigned parsed_value;
if (x3::parse(first, last, sample{}, parsed_value)) {
std::cout << s << " -> " << parsed_value << "\n";
} else {
std::cout << s << " FAIL\n";
}
};
for (std::string s : {"🌸", "48", "🤷"})
test(s);
}
Prints
🌸 -> 11
48 -> 10
🤷 FAIL
In Boost Spirit QI it was easy to template the parser so that it could be instantiated for various attribute types. It is unclear to me how to do this with X3. Consider this stripped down version of the roman numerals parser example:
#include <iostream>
#include <iterator>
#include <string>
#include <boost/spirit/home/x3.hpp>
namespace parser {
namespace x3 = boost::spirit::x3;
struct numbers_ : x3::symbols<unsigned> {
numbers_() {
add
("I" , 1)
("II" , 2)
("III" , 3)
("IV" , 4)
("V" , 5)
("VI" , 6)
("VII" , 7)
("VIII" , 8)
("IX" , 9)
;
}
} numbers;
x3::rule<class roman, unsigned> const roman = "roman";
auto init = [](auto &x) { x3::_val(x) = 0; };
auto add = [](auto &x) { x3::_val(x) += x3::_attr(x); };
auto const roman_def = x3::eps [init] >> numbers [add];
BOOST_SPIRIT_DEFINE(roman);
}
int main()
{
std::string input = "V";
auto iter = input.begin();
auto end = input.end();
unsigned result;
bool r = parse(iter, end, parser::roman, result);
if (r && iter == end) {
std::cout << "Success :) Result = " << result << '\n';
} else {
std::cout << "Failed :(\n";
}
}
I'd like to template the parser on the attribute type which is currently hardcoded as unsigned. My first guess was to replace
namespace parser {
// ...
}
with
template < typename int_t >
struct parser {
// ...
};
which is obviously too naïve. How to do this correctly?
In X3 there's not so much pain in combining parsers dynamically. So I'd write your sample as:
template <typename Attribute>
auto make_roman() {
using namespace boost::spirit::x3;
struct numbers_ : symbols<Attribute> {
numbers_() { this-> add
("I", Attribute{1}) ("II", Attribute{2}) ("III", Attribute{3}) ("IV", Attribute{4})
("V", Attribute{5}) ("VI", Attribute{6}) ("VII", Attribute{7}) ("VIII", Attribute{8})
("IX", Attribute{9}) ;
}
} numbers;
return rule<class roman, Attribute> {"roman"} =
eps [([](auto &x) { _val(x) = 0; })]
>> numbers [([](auto &x) { _val(x) += _attr(x); })];
}
See it Live On Coliru
I am looking for a sample how to pack ext types with msgpack in C++ as I am not sure about how to do this.
The only information I found is located in this section https://github.com/msgpack/msgpack-c/wiki/v2_0_cpp_packer#pack-manually.
Assumed I want to pack an object of type Foo as a msgpack ext type with an adaptor class template. How to use pack_ext and pack_ext_body? Do I have to create a "sub packer" within the template, pack my Foo data manually and then pass size of the binary data and the data itself to pack_extand pack_ext_body? It would be create if some C++ expert could give me a minimal example.
MSGPACK_API_VERSION_NAMESPACE(MSGPACK_DEFAULT_API_NS) {
namespace adaptor {
template<>
struct pack<Foo> {
template <typename Stream>
packer<Stream>& operator()(msgpack::packer<Stream>& o, Foo const& v) const {
// how to use ?
o.pack_ext(size_t l, int8_t type);
o.pack_ext_body(const char* b, size_t l);
}
}
}
}
Thanks in advance!
I got it to work with my "sub packer" idea. I do not know if it is a good and elegant solution but at least it is working:
MSGPACK_API_VERSION_NAMESPACE(MSGPACK_DEFAULT_API_NS) {
namespace adaptor {
template<>
struct pack<Foo> {
template <typename Stream>
packer<Stream>& operator()(msgpack::packer<Stream>& o, Foo const& v) const {
msgpack::sbuffer sbuf;
msgpack::packer<msgpack::sbuffer> sub_packer(sbuf);
sub_packer.pack_map(2);
sub_packer.pack("name");
sub_packer.pack(v.name);
sub_packer.pack("bar");
sub_packer.pack(v.bar);
// get binary data from sub_packer's sbuffer
size_t l = sbuf.size();
const char* b = sbuf.data();
// pass ext type and binary data to originally packer
o.pack_ext(l, 1);
o.pack_ext_body(b, l);
return o;
}
}
}
}
You can use msgpack::type::ext or msgpack::type::ext_ref.
They are defined at https://github.com/msgpack/msgpack-c/blob/master/include/msgpack/v1/adaptor/ext.hpp
Here is an example for msgpack::type::ext:
#include <sstream>
#include <cassert>
#include <msgpack.hpp>
int main() {
std::string val = "ABC";
msgpack::type::ext e1(42, val.data(), val.size());
assert(e1.type() == 42);
assert(e1.size() == 3);
assert(e1.data()[0] == 'A');
assert(e1.data()[1] == 'B');
assert(e1.data()[2] == 'C');
std::stringstream ss;
msgpack::pack(ss, e1);
auto oh = msgpack::unpack(ss.str().data(), ss.str().size());
auto e2 = oh.get().as<msgpack::type::ext>();
assert(e1 == e2);
}
Live demo:
https://wandbox.org/permlink/ESmreWNBqDdXbKSf
You can also use msgpack::type::ext_ref.
It can avoid copy operation but you need to keep the original buffer, in this case val and oh.
#include <sstream>
#include <cassert>
#include <msgpack.hpp>
int main() {
std::string val = "\x2a"; // type 42
val += "ABC";
msgpack::type::ext_ref e1(val.data(), val.size());
assert(e1.type() == 42);
assert(e1.size() == 3);
assert(e1.data()[0] == 'A');
assert(e1.data()[1] == 'B');
assert(e1.data()[2] == 'C');
std::stringstream ss;
msgpack::pack(ss, e1);
auto oh = msgpack::unpack(ss.str().data(), ss.str().size());
auto e2 = oh.get().as<msgpack::type::ext_ref>();
assert(e1 == e2);
}
Live demo:
https://wandbox.org/permlink/uYr5MFjLJqPHQgj6
I try to parse a simple list of float or int into a vector of variant. I'm using boost 1.64 on Windows (mingw 64bit).
Here is a minimal example:
#include <boost/spirit/home/x3/support/ast/variant.hpp>
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/home/x3.hpp>
#include <iostream>
#include <vector>
namespace x3 = boost::spirit::x3;
struct var : x3::variant<int, float> {
using base_type::base_type;
using base_type::operator=;
};
struct block {
bool dummy; // needed to make newer boost version compile
std::vector<var> vars;
};
BOOST_FUSION_ADAPT_STRUCT(block,
(bool, dummy),
(std::vector<var>, vars)
);
x3::rule<class var, var> const r_var = "var";
x3::rule<class block, block> const r_block = "block";
auto const r_var_def = x3::float_ | x3::int_;
auto const r_block_def = x3::attr(true) >> *x3::lit(";") >> *(r_var >> -x3::lit(","));
BOOST_SPIRIT_DEFINE(r_var, r_block);
bool parse(std::string const &txt, block &ast)
{
using boost::spirit::x3::phrase_parse;
using boost::spirit::x3::space;
auto iter = txt.begin();
auto end = txt.end();
const bool parsed = phrase_parse(iter, end, r_block, space, ast);
return parsed && iter == end;
}
int main() {
std::vector<std::string> list = {
"1, 3, 5.5",
";1.0, 2.0, 3.0, 4.0"
};
for (const auto&i : list) {
block ast;
if (parse(i, ast)) {
std::cout << "OK: " << i << std::endl;
} else {
std::cout << "FAIL: " << i << std::endl;
}
}
}
GCC 7.1 gives the following error:
..\parser\parser.cpp:41:68: required from here
..\..\win64\include/boost/spirit/home/x3/nonterminal/detai/rule.hpp:313:24: error: use of deleted function 'var::var(const var&)'
value_type made_attr = make_attribute::call(attr);
^~~~~~~~~
Any ideas, why GCC doesn't compile it? It works with Clang though.
Live on Coliru (switch to clang++ to see it work).
It seems that there is a problem using the inherited special members. Two workarounds:
using var = x3::variant<int, float>;
Alternatively:
struct var : x3::variant<int, float> {
var ( ) = default;
var (var const&) = default;
var& operator= (var const&) = default;
using base_type::base_type;
using base_type::operator=;
};