Formatowanie stringa dla własnego typu

1

Inspirowałem sie tym https://fmt.dev/latest/api.html#format-api

chciałem aby fmt obsługiwało mój typ danych

https://godbolt.org/z/nEMj6zbYG

#include <fmt/format.h>

struct MyStruct { double a, b, c, d; };

template <> struct fmt::formatter<MyStruct>: formatter<string_view>{
  // parse is inherited from formatter<string_view>.
  template <typename FormatContext>
  auto format(MyStruct c, FormatContext& ctx) const {
    string_view name = fmt::format("[a:{} b:{} c:{} d:{} ]", c.a, c.b, c.c, c.d);
    return formatter<string_view>::format(name, ctx); // << no matching member function for call to 'format'
  }
};

int main() {
   MyStruct myData{1.1, 2.2, 3.3, 4.4}; 
   fmt::print("{}", myData); // oczekiwanie [a:1.1 b:2.2 c:3.3 ]
}

ale cos nie che sie skompilowac

8

Za dokumentacją, użyj format_to:

struct MyStruct { double a, b, c, d; };

template <> struct fmt::formatter<MyStruct>: formatter<string_view>{
  // parse is inherited from formatter<string_view>.
  template <typename FormatContext>
  auto format(MyStruct c, FormatContext& ctx) const {
    return fmt::format_to(ctx.out(), "[a:{} b:{} c:{} d:{} ]", c.a, c.b, c.c, c.d);
  }
};



int main() {
   MyStruct myData{1.1, 2.2, 3.3, 4.4}; 
   fmt::print("{}", myData); // oczekiwanie [a:1.1 b:2.2 c:3.3 ]
}

https://godbolt.org/z/dqjjEosja

0

Czy to oznacza, że w C++ będzie zdetronizowane formatowanie w strumieniach << na rzecz fmt ?
Strumienie "od zawsze" było overcomplicated poza standardowymi przypadkami, głupie formatowanie w sztywnej ilości cyfr - cała linia., itd
W tym ortodoksyjnym C++ impelmentacja "własnego typu" oznacza przesilenie operatora <<

Dla mnie zawsze kuriozalne było formatowanie w pamięci - przez strstream - nigdy nie powstał lepszy ortodoksyjny na gruncie C++ odpowiednik C sprintf

Obawiam się, że zbyt duża jest masa kodu strumieniowego, aby fmt uleczyło sytuację. Raczej scenariusz Parkinsona

0

strstream has been deprecated since C++98. Użyj ostringstream Luke. — Azarien dziś, 10:06

No tak (nawet to mam widze w kodzie,. widocznie mnie jakiś warning docisnął), ale nie zmienia to istoty.
Użycie koncepcji AŻ para-pliku aby sformatować stringa. Od dawna mnie nanosekundy nie interesowały, ale podobno kiepsko z tym ...

Zastanawiam się co mnie tam najbardziej razi ... chyba najbardziej niekonsekwencja strumienia stanowego-bezstanowego (tak, wiem, na poziomie analizy pro strumień nie może być bezstanowy, bo choćby tellp() się zmienia - ale mam na mysli inne zmiany stanu niż przyjmowanie znaków)
O wydajności / ciężarze mogę nie myśleć, ale wybrać do formatowania stringa coś już samo w sobie ułomne ...

0

@kq dziękuje za pomoc

A to jak sformatować coś bardziej dziwnego niż struktura ?

Mnożenie macierzy razy wektor
fmt::print("{}", Mat4f * Vec4f);
Mat4f * Vec4f to z mojego punktu widzenia jest Vec4f , ale kompilator c++ widzi to trochę inaczej

fmt wyświetla poprawnie typ Mat4f i Vec4f ale już wynik mnożenia Mat4f * Vec4f jest problememem

https://godbolt.org/z/rxhvhxPc8

#include <Eigen/StdVector>
#include <fmt/format.h>

typedef Eigen::Matrix4f Mat4f;
typedef Eigen::Vector4f Vec4f;



template <> struct fmt::formatter<Vec4f>: formatter<string_view>{
  // parse is inherited from formatter<string_view>.
  template <typename FormatContext>
  auto format(Vec4f v, FormatContext& ctx) const {
    return fmt::format_to(ctx.out(), "[{} {} {} {}]", v[0], v[1] , v[2], v[3]);
  }
};

template <> struct fmt::formatter<Mat4f>: formatter<string_view>{
  // parse is inherited from formatter<string_view>.
  template <typename FormatContext>
  auto format(Mat4f v, FormatContext& ctx) const {
    return fmt::format_to(ctx.out(), "[{} {} {} {}]\n[{} {} {} {}]\n[{} {} {} {}]\n[{} {} {} {}]", 
        v(0,0), v(0,1) , v(0,2), v(0,3),
        v(1,0), v(1,1) , v(1,2), v(1,3),
        v(2,0), v(2,1) , v(2,2), v(2,3),
        v(3,0), v(3,1) , v(3,2), v(3,3)
        );
  }
};

int main(){

    Mat4f m0;
    m0.setIdentity();
    Vec4f p0_0(0,0,0,1) ;
    Vec4f p1_1(1,1,0,1) ;
    Vec4f p100_100(100,1,0,1) ;


    fmt::print("m0:\n{}\np0_0:{}\np1_1:{}\np100_100:{}", m0, p0_0 , p1_1, p100_100); 

    // to dziala 
    Vec4f p = m0*p0_0; 
    fmt::print("\n\n{}", p);

    // to dziala 
    fmt::print("\n\n{}", Vec4f( m0*p0_0) );
    
    // to nie dziala !!!!!!!!!!!!!!!!
    fmt::print("\n\n{}",  m0*p0_0 );


    // koza(m0*p0_0);
    return 0;
}
0

Nie czuję się aż tak mocny z szablonów, ale chyba fmt nie jest winne tego że eigen dla tego mnożenia zwraca wartość typu Eigen::Product ?

required from 'void fmt::v8::print(format_string<T ...>, T&& ...) 
[with T = {Eigen::Product<Eigen::Matrix<float, 4, 4, 0, 4, 4>, Eigen::Matrix<float, 4, 1, 0, 4, 1>, 0>&}; 
format_string<T ...> = basic_format_string<char, Eigen::Product<Eigen::Matrix<float, 4, 4, 0, 4, 4>, 
Eigen::Matrix<float, 4, 1, 0, 4, 1>, 0>&>]'
0

ta cześć c++ gdzie są szablony to dla mnie na razie wydział czarów i magii z Hogwart-u

Ale trochę magię tłumaczą te zdania :

In Eigen, arithmetic operators such as operator+ don't perform any computation by themselves, they just return an "expression object" describing the computation to be performed. The actual computation happens later, when the whole expression is evaluated, typically in operator=. While this might sound heavy, any modern optimizing compiler is able to optimize away that abstraction and the result is perfectly optimized code.

Wiec wyjaśnione

1 użytkowników online, w tym zalogowanych: 0, gości: 1