Jezor
g/Programujmy

W jaki sposób takie coś # zostało zrobione? boost::thread wygląda jak klasa szablonowa (możemy podać do niej funkcję o dowolnej sygnaturze), ale w przykładzie nie zostały w ogóle użyte dzióbki <> z typami, których musielibyśmy użyć np. przy korzystaniu z klasy std::vector (i każdej innej szablonowej):
std::vector<int> vec;

onyx

@Jezor: Niestety nie pomogę, sam dużo nie stosowałem variadic templates. Boost jest znaną biblioteką, która w pełni wykorzystuje możliwości i zawiłości języka C++ oraz zawiera w sobie najlepsze techniki programowania w tym języku. Robiona jest przez najlepszych. Nie jestem aż tak dobry, trzeba by było przejrzeć kod źródłowy (ja się nie piszę :D). Być może odpowiedź jest prostsza niż myślę, ale naprawdę nie umiem powiedzieć.

Jezor
g/Programujmy

W jaki sposób takie coś # zostało zrobione? boost::thread wygląda jak klasa szablonowa (możemy podać do niej funkcję o dowolnej sygnaturze), ale w przykładzie nie zostały w ogóle użyte dzióbki <> z typami, których musielibyśmy użyć np. przy korzystaniu z klasy std::vector (i każdej innej szablonowej):
std::vector<int> vec;

onyx

@Jezor: Na początku skojarzyło mi się to ze zmienna liczbą parametrów, ale to jest w C i na funkcjach. W C++11 wprowadzono variadic templates i jak się popatrzy w szczegółowy plik nagłówkowy boost/thread/detail/thread.hpp to faktycznie tak jest, z tym że opatrzone jest to dyrektywami warunkowymi. Jeśli wsparcia dla C++11 w kompilatorze nie ma to są tam stosowane inne techniki.

Jezor
g/Programujmy

C++, "forward declarations"
Czy ktoś może mi to wytłumaczyć, bo ni cholery nie potrafię tego zrozumieć?
Myk polega na tym, żeby nie walić #include do każdego pliku, tylko napisać deklarację używanych w nim funkcji / klas. Ale nadal gdzieś musimy dać to #include mimo wszystko...

Załóżmy, że mamy takie przykładowe pliczki:

/ A.hpp /

class A {
public:
A();
B getB();
}

/ A.cpp /

#include "A.hpp"
A::A() {}
B A::getB() { B b; return b; }

/ B.hpp /

class B {
public:
B();
}

/ B.cpp /

#include "B.hpp"
B::B() {}

No i wszystko spoko, ale kiedy chcemy skorzystać z klasy A, musimy dać #include do pliku B.hpp:

/ main.cpp /

#include "A.hpp"
#include "B.hpp" // bez tego nie zadziała
int main () {
A a;
a.getB();
return 0;
}

Co nam to daje, że nie daliśmy tego wcześniej?
I jaki ma sens taki podział na pliki, skoro chcemy użyć tylko klasy A i nie powinno nas interesować, skąd A bierze B?

onyx

@Jezor: Zaznaczyłem jak najmniej, a nie że wcale. Niezbędne pliki nagłówkowe muszą się pojawić, aby umożliwić poprawną kompilację. Jest to dobra praktyka, a nie nakaz. Akurat plik nagłówkowy iostream sam w sobie nic nie reprezentuje, zawiera jedynie odwołania do zewnętrznych obiektów, które znajdują się w innej jednostce kompilacji. Te obiekty są podstawowe i powszechnie znane, dlatego zrobiono oddzielny plik nagłówkowy tylko z nimi. Dlaczego iostream nie zawiera math.h? Często jak używam iostream również używam math.h. Strasznego mi psikusa zrobili!!! :D. Poważniej, przykładowo klasa A korzysta w swoich metodach z funkcji matematycznych (math.h), używając obiektu klasy A nie muszę o tym wiedzieć. Po co mam mieć w swoim pliku pośrednio #include <math.h> dzięki a.h, skoro ja używam tylko obiektów klasy A, nie potrzebuję żadnego pliku nagłówkowego biblioteki matematycznej. Tutaj [1] przykład oraz jego dobra analiza z klasami. Zmniejszając ilość zależność (ilości #include) minimalizujemy również niepotrzebne ich przetwarzanie w innych jednostkach kompilacji oraz zmniejszamy ewentualną rekompilacje w przypadku jakiejkolwiek zmiany w dany plik nagłówkowy [2]. Jak już wspomniałem jest to dobra praktyka, nie nakaz!!!

[1] http://www.eventhelix.com/RealtimeMantra/HeaderFileIncludePatterns.htm
[2] http://blog.knatten.org/2012/11/09/another-reason-to-avoid-includes-in-headers/

Jezor
g/Programujmy

C++, "forward declarations"
Czy ktoś może mi to wytłumaczyć, bo ni cholery nie potrafię tego zrozumieć?
Myk polega na tym, żeby nie walić #include do każdego pliku, tylko napisać deklarację używanych w nim funkcji / klas. Ale nadal gdzieś musimy dać to #include mimo wszystko...

Załóżmy, że mamy takie przykładowe pliczki:

/ A.hpp /

class A {
public:
A();
B getB();
}

/ A.cpp /

#include "A.hpp"
A::A() {}
B A::getB() { B b; return b; }

/ B.hpp /

class B {
public:
B();
}

/ B.cpp /

#include "B.hpp"
B::B() {}

No i wszystko spoko, ale kiedy chcemy skorzystać z klasy A, musimy dać #include do pliku B.hpp:

/ main.cpp /

#include "A.hpp"
#include "B.hpp" // bez tego nie zadziała
int main () {
A a;
a.getB();
return 0;
}

Co nam to daje, że nie daliśmy tego wcześniej?
I jaki ma sens taki podział na pliki, skoro chcemy użyć tylko klasy A i nie powinno nas interesować, skąd A bierze B?

onyx

@Jezor: Tzn. deklarując wcześniej class A; kompilator wie, że może mieć do czynienia z wskaźnikiem do niego i może dla niego przeznaczyć odpowiedni rozmiar. Zazwyczaj rozmiary wskaźników do różnych obiektów jest taki sam (nie mylić z rozmiarem samych obiektów), ale nie zawsze może to być zagwarantowane [1]. Przykładowo u mnie dla wskaźników do typów sizeof(char*) == sizeof(int*) == sizeof(double*) == 8 bajtów, z kolei dla wskaźników obiektów z przykładu z tego linku to sizeof(void (A::*)()) == sizeof(void (B::*)()) == sizeof(void (D::*)()) == 16 bajtów. Jak dokładnie sobie z tym radzi kompilator to nie umiem powiedzieć. Co do zmniejszenia czasu kompilacji, to używając niekompletnych deklaracji zmniejszamy ilość pojawiania się plików nagłówkowych (#include), dzięki czemu kompilator będzie je mniej przetwarzał. Jeśli chodzi o czytelność kodu to wydaje mi się, że jest to kwestia przyzwyczajenia. Dla mnie bardziej oczywiste jest, że w pliku .hpp tylko deklaruję to co później może być gdzieś przez coś używane (interfejs) i jak najmniej używam #include w pliku .hpp [2].

[1] http://stackoverflow.com/questions/399003/is-the-sizeofsome-pointer-always-equal-to-four
[2] http://programmers.stackexchange.com/questions/167723/what-should-and-what-shouldnt-be-in-a-header-file

Jezor
g/Programujmy

C++, "forward declarations"
Czy ktoś może mi to wytłumaczyć, bo ni cholery nie potrafię tego zrozumieć?
Myk polega na tym, żeby nie walić #include do każdego pliku, tylko napisać deklarację używanych w nim funkcji / klas. Ale nadal gdzieś musimy dać to #include mimo wszystko...

Załóżmy, że mamy takie przykładowe pliczki:

/ A.hpp /

class A {
public:
A();
B getB();
}

/ A.cpp /

#include "A.hpp"
A::A() {}
B A::getB() { B b; return b; }

/ B.hpp /

class B {
public:
B();
}

/ B.cpp /

#include "B.hpp"
B::B() {}

No i wszystko spoko, ale kiedy chcemy skorzystać z klasy A, musimy dać #include do pliku B.hpp:

/ main.cpp /

#include "A.hpp"
#include "B.hpp" // bez tego nie zadziała
int main () {
A a;
a.getB();
return 0;
}

Co nam to daje, że nie daliśmy tego wcześniej?
I jaki ma sens taki podział na pliki, skoro chcemy użyć tylko klasy A i nie powinno nas interesować, skąd A bierze B?

onyx

@Jezor: Oczywiście masz rację, zapewne autor nie brał tego pod uwagę i myślał tylko o obiektach. Używając "incomplete forward declarations" na daną chwilę kompilatorowi wystarcza jedynie wiedza o rozmiarze wskaźnika. Jeśli w kodzie występuje wskaźnik do obiektu / funkcji / metody kompilator już wie z jakim wskaźnikiem ma do czynienia i dobierze odpowiedni rozmiar do niego, a jeśli nie wie to wyrazi swoje niezadowolenie w dosadny sposób :D

Jezor
g/Programujmy

C++, "forward declarations"
Czy ktoś może mi to wytłumaczyć, bo ni cholery nie potrafię tego zrozumieć?
Myk polega na tym, żeby nie walić #include do każdego pliku, tylko napisać deklarację używanych w nim funkcji / klas. Ale nadal gdzieś musimy dać to #include mimo wszystko...

Załóżmy, że mamy takie przykładowe pliczki:

/ A.hpp /

class A {
public:
A();
B getB();
}

/ A.cpp /

#include "A.hpp"
A::A() {}
B A::getB() { B b; return b; }

/ B.hpp /

class B {
public:
B();
}

/ B.cpp /

#include "B.hpp"
B::B() {}

No i wszystko spoko, ale kiedy chcemy skorzystać z klasy A, musimy dać #include do pliku B.hpp:

/ main.cpp /

#include "A.hpp"
#include "B.hpp" // bez tego nie zadziała
int main () {
A a;
a.getB();
return 0;
}

Co nam to daje, że nie daliśmy tego wcześniej?
I jaki ma sens taki podział na pliki, skoro chcemy użyć tylko klasy A i nie powinno nas interesować, skąd A bierze B?

onyx

@Jezor: To czego szukasz ściślej rzecz ujmując nazywa się "incomplete forward declarations". Tutaj [1] masz przedstawiony praktycznie dokładnie ten sam przykład, który opisałeś. W [2] oraz [3] (tutaj dokładniej) masz wyjaśnione kiedy możesz/nie możesz to stosować.

[1] http://www.adp-gmbh.ch/cpp/forward_decl.html
[2] http://stackoverflow.com/questions/553682/when-can-i-use-a-forward-declaration
[3] http://www.umich.edu/~eecs381/handouts/IncompleteDeclarations.pdf

newinuto
g/pogadachy

Kurczę, zniknęły wszystkie blokady grup, które wczoraj założyłam. Zauważyłam to dzisiaj po zalogowaniu się. @duxet

onyx

@newinuto: Zapewne ma to związek ze zmianami o których duxet wspomniał niżej. Coś mi się wydaje, że trzeba będzie blokady ustawić na nowo :)

halotomi
g/Strimoid

Jak do cholery usunąć źle dodane powiązane?

onyx

@halotomi: Narazie najlepiej jest usunąć całą treść i dodać ją ponownie. Narazie powiązane nie można edytkować ani usuwać.

zskk
g/pogadachy

oficjalnie zapowiadam sie - przechodze z stri.ms na strimoid.pl

onyx

@n30n: Ja wykopu się nie tykam, jestem na nim spalony. Kiedyś administracja manipulowała głosami znalezisk (głosy oddane na znalezisko były nie ważne). Po tej akcji duża fala krytyki na nich spłynęła i m.in. ja dostałem bana. Ostatecznie poprosiłem o usunięcie konta. Już nigdy tam nie zaglądałem. Wykop się dla mnie skończył.

zskk
g/pogadachy

oficjalnie zapowiadam sie - przechodze z stri.ms na strimoid.pl

onyx

@zskk: Ja kibicuje obu projektom (stri.ms oraz strimoid), ale mi osobiście bardziej strimoid odpowiada, mimo że wiele jest tutaj do zrobienia. Nie da się ukryć, że na stri.ms jest dużo fajnych ludzi, którzy już się tam zadomowili. Co do strims.pl, niektórzy wielcy zwolennicy jego powrotu chyba nie takie wyobrażali sobie jego zmartwychwstanie (bez bazy, właściwie bez niczego). Nowi użytkownicy nie są świadomi co zaszło i nie wiedzą o naszym istnieniu. Na pewno nie zaszkodzi promowanie strimoida :)

zskk
g/pogadachy

oficjalnie zapowiadam sie - przechodze z stri.ms na strimoid.pl

onyx

@zskk: miło jak ktoś nowy będzie się udzielał na strimoidzie :), bo wielu nas na razie nie ma

gav
g/pogaduchy

@duxet ratuj! dodało mi trzy razy treść!

onyx

@gav: Jak wejdziesz do swojej treści i nie minął czas 15 minut od jej dodania to po prawej stronie obok przycisków "Subskrybuj" oraz "Zablokuj" powinien pojawić się przycisk "Usuń".

gav
g/pogaduchy

@duxet ratuj! dodało mi trzy razy treść!

onyx

@gav: Też ją zauważyłem. Trzeba czekać na duxet-a.

gav
g/pogaduchy

@duxet ratuj! dodało mi trzy razy treść!

onyx

@gav: zapewne duxet nad czymś pracuje i pewnie coś poszło nie tak :)

gav
g/pogaduchy

@duxet ratuj! dodało mi trzy razy treść!

onyx

@gav: A nie możesz je usunąć? Już można usuwać treści.