{fmt} poate converti implicit o clasă, dar nu un vector de clasa

0

Problema

Deci am urmatoarele struct:

struct Snowflake {
    Snowflake() : _value(0) {}
    Snowflake(uint64_t value) : _value(value) {}
    Snowflake(std::string value) : _value(std::stoull(value)) {}
    Snowflake(const Snowflake &) = default;

    operator uint64_t &() { return _value; }

    operator uint64_t() const { return _value; }

    operator std::string() const { return std::to_string(_value); }

    Snowflake &operator=(uint64_t val) {
        _value = val;
        return *this;
    }

    Snowflake &operator=(const std::string &str) {
        _value = std::stoull(str);
        return *this;
    }

    Snowflake &operator=(const Snowflake &s) {
        _value = s._value;
        return *this;
    }

  protected:
    uint64_t _value;
};

Dacă am declara Snowflake snowflake = 336227221100429313; pot folosi fmt::print("Snowflake: {}", snowflake); de exemplu, doar bine, dar nu-l pot folosi std::vector<Snowflake> snowflakes{164234463247597568, 106615803402547200, 268487751370801152}; cu fmt::print("Snowflakes: {}", snowflakes); I a lua următoarea eroare:

In file included from -snip-/cmake-build-debug/_deps/fmt-src/include/fmt/format.h:48,
                 from -snip-/snowflake.hh:8,
                 from -snip-/main.cpp:2:
-snip-/cmake-build-debug/_deps/fmt-src/include/fmt/core.h: In instantiation of ‘constexpr fmt::v8::detail::value<Context> fmt::v8::detail::make_arg(T&&) [with bool IS_PACKED = true; Context = fmt::v8::basic_format_context<fmt::v8::appender, char>; fmt::v8::detail::type <anonymous> = fmt::v8::detail::type::custom_type; T = std::vector<Snowflake>&; typename std::enable_if<IS_PACKED, int>::type <anonymous> = 0]’:
-snip-/cmake-build-debug/_deps/fmt-src/include/fmt/core.h:1807:77:   required from ‘constexpr fmt::v8::format_arg_store<Context, Args>::format_arg_store(T&& ...) [with T = {std::vector<Snowflake, std::allocator<Snowflake> >&}; Context = fmt::v8::basic_format_context<fmt::v8::appender, char>; Args = {std::vector<Snowflake, std::allocator<Snowflake> >}]’
-snip-/cmake-build-debug/_deps/fmt-src/include/fmt/core.h:1824:38:   required from ‘constexpr fmt::v8::format_arg_store<Context, fmt::v8::remove_cvref_t<Args>...> fmt::v8::make_format_args(Args&& ...) [with Context = fmt::v8::basic_format_context<fmt::v8::appender, char>; Args = {std::vector<Snowflake, std::allocator<Snowflake> >&}]’
-snip-/cmake-build-debug/_deps/fmt-src/include/fmt/core.h:3156:44:   required from ‘void fmt::v8::print(fmt::v8::format_string<T ...>, T&& ...) [with T = {std::vector<Snowflake, std::allocator<Snowflake> >&}; fmt::v8::format_string<T ...> = fmt::v8::basic_format_string<char, std::vector<Snowflake, std::allocator<Snowflake> >&>]’
-snip-/main.cpp:10:44:   required from here
-snip-/cmake-build-debug/_deps/fmt-src/include/fmt/core.h:1680:7: error: static assertion failed: Cannot format an argument. To make type T formattable provide a formatter<T> specialization: https://fmt.dev/latest/api.html#udt
 1680 |       formattable,
      |       ^~~~~~~~~~~

Am încercat declarând următoarele:

template <> struct fmt::formatter<Snowflake> : formatter<uint64_t> {
    template <typename FormatContext>
    auto format(Snowflake s, FormatContext &ctx) {
        return formatter<uint64_t>::format(s, ctx);
    }
};

dar asta nu a rezolvat problema. Am nevoie pentru a celare o fmt::formatter pentru std::vector<Snowflake>? Ce ar fi cel mai simplu mod de a face asta?

c++ fmt implicit stdvector
2021-11-13 15:49:48
1

Cel mai bun răspuns

1

Acesta funcționează în versiunea actuală a {fmt} (https://godbolt.org/z/98qzcb8r9):

#include <fmt/ranges.h>

...

auto snowflake = Snowflake(336227221100429313);
fmt::print("Snowflake: {}\n", snowflake);
auto snowflakes = std::vector<Snowflake>{164234463247597568, 106615803402547200, 268487751370801152};
fmt::print("{}\n", snowflakes);

printuri

Snowflake: 336227221100429313
[164234463247597568, 106615803402547200, 268487751370801152]

Bazându-se pe conversie implicită nu este recomandată.

2021-11-14 14:33:19

Ar fi de menționat în răspunsul la sine că #include <fmt/ranges.h> este necesar pentru acest lucru, spre deosebire de doar #include <fmt/format.h> sau <fmt/core.h>.
Nathan Pierson

@NathanPierson Da, asta a fost. Inclusiv că a reparat-o. Ar trebui să meargă într-un răspuns pe cont propriu, sau ar trebui să fie editate?
Aido

Adăugat include la fel de bine.
vitaut

În alte limbi

Această pagină este în alte limbi

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................