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: 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

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: 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: 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: 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

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

Widząc dalej - kosmi...

Widząc dalej - kosmiczny teleskop Jamesa Webba

Następca teleskopu Hubbla. W odróżnieniu od swojego poprzednika, ma on prowadzić obserwacje w podczerwieni. Został nazwany na cześć Jamesa Webba, drugiego administratora NASA. Wystrzelenie w kosmos zaplanowane jest na rok 2018.

preview 1 comment Wszechświat onyx youtu.be 0

Widząc dalej - kosmi...

Widząc dalej - kosmiczny teleskop Jamesa Webba

Następca teleskopu Hubbla. W odróżnieniu od swojego poprzednika, ma on prowadzić obserwacje w podczerwieni. Został nazwany na cześć Jamesa Webba, drugiego administratora NASA. Wystrzelenie w kosmos zaplanowane jest na rok 2018.

preview 1 comment Wszechświat onyx youtu.be 0