[C++]Zmienna liczb argumentów o nieznanym typie

Witam, otóż piszę sobie loger i chciałbym, żeby można go było używać w ten sposób:

log << "lalala" << 85 << 0.34f << 'c';

Poczytałem w internecie o funkcjach z nagłówka cstdarg ale niestety wymagają one podania typu argumentu a ja potrzebuję, żeby można było wpisać dowolny typ wbudowany bez jego sprawdzania. Wiem, że jakoś się da bo tak działa np. std::cout. Wie ktoś jak to wykonać? :slight_smile:

Wystarczy przeładować operator << dla typów wbudowanych(najlepiej wszystkich), skorzystać z szablonów i/lub czegoś, co już jest(stringstream).

Tzn? bo jeśli zrobię coś takiego:

template void operator<< (TYPE text)

to mam całą hordę błędów przy zrobieniu np:

log << "ad" << 65555 <<;

edit. Ok dzięki już sobie poradziłem, trzeba było:

template Logger& operator<< (TYPE text) { Write(text); return (*this); }

Chłopie. masz w sygnaturce C++ programmer, a nie potrafisz w operatora strumieniowego przeciążyć? Z którego drzewa spadłeś? Naucz się odpowiedzialności za słowa.

  1. Dla każdego typu podstawowego dostępny jest przeciążony operator<< w klasie ostream i pochodnych. Nie musisz go sam pisać

  2. Dla każdego typu zdefiniowanego przez programistę trzeba samodzielnie przeciążyć operator strumieniowy. Zwykle zaprzyjaźnia się funkcję z konkretną klasą. Prototyp funkcji ma wyglądać następująco:

    friend std::ostream& operator<<(std::ostream&, const Nazwa_klasy&)

  3. Nie dotykaj szablonów jak nie znasz podstaw.

Błędnie założyłeś, że dziedziczy z std::ostream.

To NIE JEST operator strumieniowy(choć Wiki tak to nazywa w kontekście iostream). To jest operator przesunięcia bitowego w lewo. Jak dla mnie używanie go w innym celu jest bez sensu i tylko zaciemnia kod(do autora: już lepsze byłyby łańcuchowe wywołania metody Write).

Znów błędnie zakładasz, że nie zna podstaw, a nawet jeśli ich nie zna to tego nie wie(i zdefiniuj “podstawy”). Więc tak, dotykaj szablonów jeśli mają Ci uprościć kod.

Hmm ja także czekam na definicję podstaw. Dla mnie jest to po prostu znajomość konstrukcji języka a nie umiejętność recytowania z pamięci STL-a. No i już sobie poradziłem więc w czym problem?

  1. Dobra, błędnie założyłem że WOJTEK64 dziedziczy po ostream. Tylko czy się pomyliłem? Poza tym zdecydowaną większość takich problemów rozwiązuje się dziedziczą po ostream.

  2. TO JEST OPERATOR STRUMIENIOWY. Nie tylko w wiki jest tak nazywany, jest mnóstwo literatury które używa tego określnienia (np. Thiking ic C++, Bruce Eckel).

Nie widzę też, dlaczego uzywając operatora strumieniowego, miałbym zaciemniać kod. Zgodnie z logiką Fiołka najlepiej w ogóle nie przeciążać operatorów.

Poza tym metoda Write nie jest chyba natywną metodą C++, tylko pochodzi z .NET (nie jestem do końca pewien). IHMO pisanie kodu zależnego od czegoś, jeśli można napisać kod niezależny do tylko dlatego, że coś nam się nie podoba, jest zwykłą nieodpowiedzialnością. Nawet jeśli mogę później przeportować aplikację, to będę miał więcej pracy.

W ogóle Fiołek, gadasz jak programista Javy.

  1. Nie wspominam nic o STL, co więcej WOJTEK64 daleko Ci jeszcze do STL. Trzy podstawowe umiejętności: zdefiniowanie problemu, nazwanie problemu, samodzielne rozwiązanie problemu. Problem może sam rozwiązałeś. Tylko jak widać po tytule i przebiegu masz mimo wszystko jeszcze dużo do nadrobienia. Jeśli chodzi o sprawy techniczne, od razu widać, że nie potrafisz przeciążać operatorów. Gdybyś to umiał, rozwiązanie problemu byłoby dla Ciebie oczywiste i nie napisałbyś tego wątku. Na tej podstawie twierdzę, że nie znasz podstaw. Przyznam się, że nie chcę mi się rozpisywać na temat podstaw. Proponuje inne wyjście, napisz na priv a ja Ci udowodnię, że nie znasz C++. Wszystkich innych chętnych też zapraszam.

Ok operator strumieniowy - nazwa wzięła się od zastosowania operatora przesunięcia bitowego w dość nietypowy sposób przy wyodrębnianiu się C++ z C. Przeciążanie operatorów nie jest dla mnie problemem (przynajmniej dotychczas), po prostu pierwszy raz zaszła u mnie potrzeba by przeciążyć << a przy deklaracji void operator<< za nic nie chciało mi to działać. Na PW nie zamierzam ci pisać, nie mam ochoty na bezsensowne batalie radem z gimnazjum, jeśli rzeczywiście nie ogarniam podstaw to i tak z czasem się nauczę, na razie wolałbym dokończyć projekt, temat uważam za zamknięty Amen :slight_smile:

W polskim tłumaczeniu mogli go nazwać nawet “szalona krowa”, pytanie co na to oficjalna dokumentacja.

Myślę, że już wszystko udowodniłeś tym stwierdzeniem:

■■■? Nie widziałem, by gdziekolwiek, cokolwiek spoza STL dziedziczyło z std::ostream, bo to znaczny przerost formy nad treścią(jaki jest tego sens? jest dużo lepszych rozwiązań), ale przyznaję, że mało widziałem i się nie znam(acz nadal jestem przekonania, że to jest dzikie rozwiązanie).

I inne mnóstwo nawet nie używa tej części STL(albo ogranicza się do niewielkiej części). To, że część osób uznała takie rozwiązanie, nie znaczy, że jest dobre. Dla mnie zaciemnia kod i wolę łańcuchowe wywołanie Write(albo Write(std::string) i sposób a’la boost::format).

Tego w ogóle nie rozumiem. Od czego zależną? Co zależne? Co nie jest zależne od niczego?

Poznaję Javę, to źle że się rozwijam?

I lol’d :smiley: No wybacz, ale nikt nigdy nie zdefiniował sobie funkcji/metody(jak zwał tak zwał) Write w jakiejś klasie w C++.

Ale czemu niby źle przeciążył? Nie jest wymogiem, by operator << zwracał referencję do obiektu tej samej klasy. Jedyną restrykcją jest to, że jest dwuargumentowy. Tyle.

EDIT:

Zapomniałbym…

Nie wmawiaj mi, jaką ja mam logikę. Operatory matematyczne są od zastosowań matematycznych(i pokrewnych), operator przesunięcia bitowego w lewo nim jest i takie jest jego zadanie.

@somekid

  1. Nie mam standardu na dysku i nie chce mi się (chociażby przez przekorę) go szukać. Za to mam “The C++ Programming Language” Bjarne Stroustrup w wersji angielskiej i tam jest …(uwaga, suspens) “stream operator”

  2. W klasie Console jest statyczna metoda Write

@Fiołek

Domyślne otwarcie pliku? Ustawienie domyślnych flag? Przekierowanie standardowego wyjścia? Powodów dla których można ostream jest kilka. Poza tym, żadna klasa z STL nie dziedziczy po ostream. Nie myl standardowej biblioteki z STL. STL jest częścią standardowej biblioteki. To, że coś (w tym wypadku standardowa biblioteka) jest implementowana za pomocą szablonów i jest w przestrzeni nazw std, nie oznacza że należy automatycznie do STL.

Nie do końca rozumiem, o co Ci chodzi. Wytłumacz mi dlaczego inne części STL (czy raczej std) mają wykorzystywać operator strumieniowy (chyba o to Ci chodzi). Jeśli nic nie drukuję do strumienia to mam wykorzystywać operator strumieniowy dla ozdoby? Jeśli o tym nie wiesz (a z Twojej wypowiedzi wynika że nie wiesz), to klasy z std nic nie drukują, więc po co mają wykorzystywać operator strumieniowy?

Poza tym jeśli chcesz sobie podyskutować na temat wyboru operatora do przeciążenia to odsyłam do komitetu standaryzującego. Bo przecież o tą “część osób” Ci chodziło.

I jeszcze jedno, co masz na myśli pisząc “łańcuchowe wywołanie Write”. Proszę nie tylko o przykład kodu, ale jakieś źródła tej nazwy (tytuły książek etc).

Dobra nie wiem czego nie rozumiesz, ale na pewno masz rację.

Dobrze, że się rozwijasz. Tylko IHMO Java (ani C#) odmóżdżają. Z resztą widać to po Twoich argumentach.

Już napisałem o tym wyżej.

Bo nie działało tak jak powinno.

Rozumiem, że operator konkatacji w Javie jest zastosowaniem matetycznym lub pokrewnym. Bo wiesz, w Javie ogólnie nie ma przeciążania operatów i coś takiego może zaciemniać kod.

A w Afryce jest Tanzania. Jaki związek ma jakaś metoda z .NET z tym, o czym pisał Fiołek w wątku o C++?

Tak mi się zaczyna wydawać, że ta “dyskusja” nie ma sensu, ale…

Wolę cstdio albo nawet WinAPI, iostream i “domyślne flagi” nie są mi potrzebne do niczego, pewnie większości też. Dodatkowo od tego jest dokumentacja. I co można ostream?

http://www.cplusplus.com/reference/iostream/ostream/

Za Wikipedią:

Wystarczy?

Method chaining(polecam również zapoznać się z Fluent interface).

Czy odnosiłem się do fragmentu o STL? Nie. Odnosiłem się do wątku o literaturze(czy też projektów, czytaj: aplikacji), który sam zacząłeś. Naprawdę, to nie ułatwia czytania kodu. Spróbuj teraz zapomnieć o tym, że znasz C++, ale znasz np. C#. W pracy/w szkole/etc. masz za zadanie przeanalizować kod C++ wykorzystujący “operator strumieniowy”(ale ty go nie znasz!). Widzisz taki kod:

log << "lalala" << 85 << 0.34f << 'c'; [/code]

Ile czasu zajmie Ci rozszyfrowanie tego? A ile zajęłoby rozszyfrowanie tego:

[code=php]log.Write(“lalala” + 85 + 0.34f + ‘c’); 

(przyjmijmy, że mamy w języku obsługę operatora konkatenacji dla użytych typów, albo mamy rzutowanie implicit na string)?

Albo nawet tego:

log.Write("lalala").Write(85).Write(0.34f).Write('c') [/code]

zakładając, że mamy przeładowania Write dla tych typów(możliwe w C++), albo rzutowanie implicit na string(niemożliwe, przynajmniej na razie).

? Zacznijmy od tego, że komitet standaryzacyjny nie jest “alfą i omegą”. Istnieje też coś takiego jak zdrowy rozsądek, zdanie większości(tutaj ciężko je wyznaczyć, przyznaję), zdanie mądrzejszych(nie, nie mnie).

Jaki ma związek nazwa funkcji/metody z językiem(Write)? Podaj mi przykład jakiegoś, jakiegokolwiek programu niezależnego od niczego.

Przepraszam, że staram się być w miarę obiektywny i mieć poparcie w swoich tezach, już nie będę. :frowning:

Odpowiem jak “już było wcześniej”:

Nigdzie nie ma wymogu, by działało tak jak Ci się wydaje, że powinno. Działało tak jak zostało napisane, i to, że kompilator to przepuścił mówi samo za siebie.

Zobacz sobie np. to. Uprzedzając, VS też to przepuszcza

Zastanów się teraz czym jest string(ciąg znaków). Tak, ciąg! Nawet w nazwie jest ciąg! A coś takiego jak konkatenacja ciągów jest pojęciem matematycznym. Przyznam, że preferuję używać operatorów, gdy operuję na wektorach czy macierzach, ale bez problemu zaspokajam się metodami typu add, multiply czy dotProduct.