Mechanizm promocji w C++

18.05.2010 @ 11:33:28 by Rafał Kozik | C++ szablony programowanie

W standardzie języka C (i C++) opisany jest mechanizm promocji, który polega na automatycznej konwersji z mniejszego typu na większy (np. short na int). Istnieją dwa rodzaje promocji:

  • promocja całkowita (ang. integral promotion) -- konwersja liczb całkowitych
  • promocja zmiennoprzecinkowa (ang. floating point promotion) -- konwersja liczb zmiennoprzecinkowych

Zachowanie to jest bardzo intuicyjne. Dodatkowo, w przypadku użycia funkcji o zmiennej ilości argumentów (tzn. użycia ...), małe typy całkowitoliczbowe ulegają promocji do int / unsigned int, a float do double. To jest już trochę mniej naturalne, ale ta wiedza może czasami się przydać (choćby do tego, żeby tego nie używać ;)).

W C++, z mechanizmem promocji wiąże się dodatkowy problem przy pisaniu funkcji szablonowych. Typowa implementacja max wygląda tak:

template <typename T>
const T& max(const T& a, const T& b)
{
    return (a > b) ? a : b;
}

Wszystko byłoby fajnie, gdyby nie fakt, że wywołanie max(1.0f, 2.0) się nie skompiluje. Da się to rozwiązać bawiąc się trochę szablonami -- o tym w dalszej części.


Szablony w C++

17.05.2010 @ 20:27:08 by Rafał Kozik | C++ szablony programowanie

Szablony są bardzo ciekawym elementem języka C++. Zdarza mi się przeglądać nie mój kod i często mam wrażenie, że ich użycie (poza wykorzystywaniem biblioteki STL) ogranicza się do tworzenia uniwersalnych funkcji i struktur danych, a to dopiero wierzchołek góry lodowej.

Co właściwie można osiągnąć za pomocą szablonów?

  • implementacja uniwersalnych funkcji i struktur danych
  • wykonywanie obliczeń w trakcie kompilacji
  • podejmowanie decyzji w trakcie kompilacji
  • generowanie zoptymalizowanego kodu źródłowego
  • budowanie uniwersalnych wzorców zachowań

Ostatnie dwa punkty mogą wymagać dodatkowego wyjaśnienia.

Jeżeli chodzi o generowanie zoptymalizowanego kodu źródłowego, to za pomocą szablonów możemy generować kod, który nie ustępuje pod względem wydajności ręcznej implementacji. Możliwa jest implementacja klasy wektora (matematycznego), gdzie rozmiar jest parametrem szablonu, a wydajność jest zawsze taka jak w przypadku optymalnej implementacji dla każdego rozmiaru z osobna.

W kwestii budowania uniwersalnych wzorców zachowań sprawa jest trochę bardziej skomplikowana -- mam tu na myśli programowanie z użyciem wytycznych, które opisuje Andrei Alexandrescu w książce "Modern C++ Design". Podczas implementacji często istnieje wiele możliwych (i sprzecznych ze sobą) rozwiązań. Czy kod ma być thread-safe? Jak ma wyglądać alokacja pamięci? Decyzje o tym powinien podejmować użytkownik kodu w zależności od swoich potrzeb i takie właśnie zachowanie można osiągnąć używając szablonów w C++.

Mechanizm szablonów ma bardzo dużą siłę ekspresji, rzadko spotykaną w innych językach. Aby nie pozostać gołosłownym, w najbliższym czasie pojawi się seria wpisów z użyciem szablonów.