• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Szablony funkcji i enable_if

Object Storage Arubacloud
0 głosów
302 wizyt
pytanie zadane 10 lutego 2017 w C i C++ przez Token Nowicjusz (200 p.)
edycja 11 lutego 2017 przez Token

Witam, mam taki kod:

template < typename T= typename std::enable_if< std::is_base_of<T,sf::Drawable>::value>::type >
bool drawCollection(std::vector<T> *collection);
template<typename T>
inline bool Scene::drawCollection(std::vector<T>* collection)
{
	for (auto&var : collection)
		var.draw();

	return true;
}

gdzie każdy obiekt kolekcji z racji na użycie enable_if będzie miał metodę .draw, niestety wyskakują takie błędy:

Severity    Code    Description    Project    File    Line    Suppression State
Error    C2065    'var': undeclared identifier   


Severity    Code    Description    Project    File    Line    Suppression State
Error    C2228    left of '.draw' must have class/struct/union    

Severity    Code    Description    Project    File    Line    Suppression State
Error    C3312    no callable 'begin' function found for type 'std::vector<mv::Cell,std::allocator<_Ty>> *' 

Severity    Code    Description    Project    File    Line    Suppression State
Error    C3312    no callable 'end' function found for type 'std::vector<mv::Cell,std::allocator<_Ty>> *'  

wszystkie tyczą się tej pętli
 

ps: a no i niestety tę metodę dalej da się wywołać z innymi klasami...

2 odpowiedzi

+1 głos
odpowiedź 10 lutego 2017 przez criss Mędrzec (172,590 p.)
wybrane 10 lutego 2017 przez Token
 
Najlepsza

http://en.cppreference.com/w/cpp/types/enable_if

W drugim parametrze template-a std::enable_if musisz podać, co ma się kryć pod std::enable_if<true>::type. Domyślnie jest to void. Także próbujesz iterować po vectorze obiektów typu void.

Jeszcze jedno:

for (auto&var : collection)
        var.draw();

collection jest wskaźnikiem, więc powinno być

for (auto&var : *collection)
        var.draw();

Kolejny błąd:

std::is_base_of<T,sf::Drawable>::value

Pomyliłeś kolejność parametrów. Powinno być, żeby to miało jakiś sens.

std::is_base_of<sf::Drawable, T>::value

Korzystaj z dokumentacji, plox

komentarz 10 lutego 2017 przez Token Nowicjusz (200 p.)

fakt, nie zwróciłem uwagi na ten wskaźnik, czyli jeśli wiem, że klasa dziedziczy z sf::Drawable to mam zrobić coś takiego?

		template < typename T= typename std::enable_if< std::is_base_of<T,sf::Drawable>::value,sf::Drawable>::type>

Po zamienieniu na to dalej jest błąd taki:

Severity    Code    Description    Project    File    Line    Suppression State
Error    C2228    left of '.draw' must have class/struct/union

komentarz 10 lutego 2017 przez criss Mędrzec (172,590 p.)
Dopisałem jeszcze jeden błąd do mojej odpowiedzi. Luknij
komentarz 10 lutego 2017 przez Token Nowicjusz (200 p.)
dalej ten błąd z ostatniego mojego komentarza
komentarz 10 lutego 2017 przez criss Mędrzec (172,590 p.)

czyli jeśli wiem, że klasa dziedziczy z sf::Drawable to mam zrobić coś takiego?

Jeśli chcesz, żeby domyślnie (o ilewartość z std::is_base_of da true) za T przyjmowane było sf::Drawable, to tak. Po zamienieniu kolejnością argumentów w is_base_of o czym już wspominałem.

komentarz 10 lutego 2017 przez Token Nowicjusz (200 p.)
        template < typename T= typename std::enable_if< std::is_base_of<sf::Drawable,T>::value,sf::Drawable>::type>

właśnie z tym ułożeniem jest ten błąd:

Severity    Code    Description    Project    File    Line    Suppression State 
Error    C2228    left of '.draw' must have class/struct/union

 

komentarz 10 lutego 2017 przez criss Mędrzec (172,590 p.)
Przede wszystkim: w SFML rysuje się za pomocą obiektu okna (sf::Window/sf::RenderWindow itd.). Metoda sf::Drawable::draw jest prywatna (konkretnie to protected, ale żadna różnica z zewnątrz). Moja rada: czytaj dokumentacje, bo piszesz kompletnie po omacku. Po prostu czytaj zanim użyjesz danej klasy. To raczej nie jest powodem tego błędu, ale jeśli to nie pomoże, to nie widze nic więcej.

Btw. to jest jedyny błąd teraz?
komentarz 10 lutego 2017 przez Token Nowicjusz (200 p.)
tak, jedyny
komentarz 10 lutego 2017 przez criss Mędrzec (172,590 p.)
Erm chwila...

Jak ty chcesz kiedykolwiek mieć vector obiektów sf::Drawable. sf::Drawable jest tylko interfejsem (nie da się utworzyć obiektów tej klasy). Sens miałby vector wskaźników na Drawable...

Poza tym.. Nawet nie mam pewności w jakiej instancji tego template-a wyrzuca ten błąd. Jeśli jako parametr template-a swojej funkcji dajesz int czy inny typ podstawowy, to error miałby sens.
komentarz 11 lutego 2017 przez Token Nowicjusz (200 p.)

uporałem się :) A to jeszcze zadam dodatkowo pytanie, jak zrobić coś podobnego z klasami?

gdy zrobię tak:

	template < typename T = typename std::enable_if< std::is_base_of<sf::Texture,T>::value, T>::type>

to i tak pozwala tworzyć obiekt nawet z floatem

komentarz 11 lutego 2017 przez criss Mędrzec (172,590 p.)
W takim razie nie mam pojęcia. Powinno wyrzucać błąd kompilacji dla wszystkich typów nie dziedziczących z sf::Texture.

Tylko chwila... To nie bardzo ma sens. Domyślny argument (typ przyjęty za T) ma być ustalony w oparciu o T, które jest nieznane jeśli w ogóle dochodzi do momentu ustalania domyślnego argumentu. Zrób to tak, jak pokazał MetGang.
0 głosów
odpowiedź 10 lutego 2017 przez MetGang Nałogowiec (34,360 p.)

Osobiście polecam ten sposób:

#include <SFML/Graphics.hpp>

template <typename T, typename std::enable_if<std::is_base_of<sf::Drawable, T>::value, int>::type = {}>
bool DrawCollection(std::vector<T>& Collection, sf::RenderTarget& Target, sf::RenderStates& States)
{
    for(auto& Var : Collection) Target.draw(Var, States);

    return true;
}

int main()
{
    sf::RenderWindow Target;
    sf::RenderStates States;
    sf::Sprite Spr;
    std::vector<sf::Sprite> Vec;
    Vec.push_back(Spr);

    DrawCollection(Vec, Target, States);
}

Ten miszmasz w template - sprawdzony sposób - ma za zadanie wywalić błąd kompilacji. gdy prześlesz vector złych obiektów.

Render w SFMLu działa jak działa i musisz mieć jakiś Target, na którym możesz rysować i (opcjonalnie) RenderStates dla efektów. Da się to zrobić inaczej, ale ten sposób przedstawiony przeze mnie jest dość prosty. Jeśli masz to w jakiejś klasie to dobrze by było trzymać te zmienne właśnie w niej).

komentarz 10 lutego 2017 przez criss Mędrzec (172,590 p.)
edycja 10 lutego 2017 przez criss

Zastanawia mnie  tylko = {} na końcu. Po co? I... to się kompiluje?

edit, dobra, nieważne. Coś mi mózg nie zaskoczył XD Anyway i tak zbędne te nawiasy.

komentarz 11 lutego 2017 przez MetGang Nałogowiec (34,360 p.)

Niekoniecznie zbędne, coś inaczej musisz mieć :p

To jest domyślna inicjalizacja zmiennej (w tym wypadku inta), równie dobrze mógłbyś dać = 0.

komentarz 11 lutego 2017 przez criss Mędrzec (172,590 p.)
Tak, ale ten int nawet nie ma nazwy, więc go nie użyjesz w żaden sposób :P Nie przeszkadza, ale też nie pomaga.
komentarz 11 lutego 2017 przez MetGang Nałogowiec (34,360 p.)

Tworzenie tego typu funkcji dla sf::Drawable ogólnie nie ma sensu :p Kompilator i tak wywali błąd. Lepszy już static_assert.

Co do tego template to prawda nie posiada on nazwy, nie użyjesz go - on jest tylko po to, aby wywalić błąd, gdy warunek nie zostanie spełniony lub nakierować kompilator na odpowiednią funkcję. Taka wielozmienna specjalizacja szablonu.

Osobiście używałem tego przy przeciążaniu szablonu konstruktora dla kontenera zmiennej w języku skryptowym (coś na wzór std::any):

Var var1 = 10;
Var var2 = "lol";
Var var3 = MyObject();

Wiadomo, w każdym wypadku potrzebny jest inny konstruktor, ale też chciałbym aby dla każdego inta (char, short, int, long, long long i unsigned) był jeden konstruktor i dla każdej liczby zmiennoprzecinkowej też jeden (float, double, long double) i robienie N konstruktorów można zastąpić 1 szablonowym.

Może brzmi to dziwnie i zaplątanie, ale w moim wypadku było to dobre rozwiązanie ^^

Podobne pytania

0 głosów
0 odpowiedzi 81 wizyt
0 głosów
1 odpowiedź 272 wizyt
pytanie zadane 28 września 2020 w C i C++ przez Whiskey_Taster Pasjonat (15,610 p.)
+2 głosów
2 odpowiedzi 776 wizyt
pytanie zadane 11 marca 2018 w C i C++ przez Jakub 0 Pasjonat (23,120 p.)

92,555 zapytań

141,403 odpowiedzi

319,554 komentarzy

61,940 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...